diff --git a/.gitignore b/.gitignore index f1b5b48c..33de6873 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,10 @@ captures/ # IntelliJ *.iml +.idea/ +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml .idea/workspace.xml .idea/tasks.xml .idea/gradle.xml @@ -92,3 +96,4 @@ lint/tmp/ # Android Profiling *.hprof gradle.properties + diff --git a/ShimmerAndroidInstrumentDriver/.gitignore b/ShimmerAndroidInstrumentDriver/.gitignore index 0b7b04c2..cecbba34 100644 --- a/ShimmerAndroidInstrumentDriver/.gitignore +++ b/ShimmerAndroidInstrumentDriver/.gitignore @@ -38,6 +38,10 @@ captures/ # IntelliJ *.iml +.idea/ +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml .idea/workspace.xml .idea/tasks.xml .idea/gradle.xml diff --git a/ShimmerAndroidInstrumentDriver/.idea/compiler.xml b/ShimmerAndroidInstrumentDriver/.idea/compiler.xml deleted file mode 100644 index 61a9130c..00000000 --- a/ShimmerAndroidInstrumentDriver/.idea/compiler.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/ShimmerAndroidInstrumentDriver/.idea/gradle.xml b/ShimmerAndroidInstrumentDriver/.idea/gradle.xml deleted file mode 100644 index e20f0d5a..00000000 --- a/ShimmerAndroidInstrumentDriver/.idea/gradle.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/ShimmerAndroidInstrumentDriver/.idea/misc.xml b/ShimmerAndroidInstrumentDriver/.idea/misc.xml deleted file mode 100644 index 58918f50..00000000 --- a/ShimmerAndroidInstrumentDriver/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/build.gradle b/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/build.gradle index 7d389c4b..d005bc33 100644 --- a/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/build.gradle +++ b/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/build.gradle @@ -8,7 +8,7 @@ apply plugin: 'maven-publish' version = '3.0.72Beta' android { - compileSdkVersion 25 + compileSdkVersion 26 lintOptions { abortOnError false @@ -18,7 +18,7 @@ android { // Enabling multidex support. multiDexEnabled true minSdkVersion 14 - targetSdkVersion 14 + targetSdkVersion 26 } buildTypes { @@ -104,13 +104,13 @@ dependencies { compile files('libs/ShimmerBiophysicalProcessingLibrary_Rev_0_11.jar') compile files('libs/AndroidBluetoothLibrary.jar') compile files('libs/androidplot-core-0.5.0-release.jar') - implementation (group: 'com.shimmerresearch', name: 'shimmerbluetoothmanager', version:'0.10.0_alpha'){ + implementation (group: 'com.shimmerresearch', name: 'shimmerbluetoothmanagerdev', version:'JA-90_v0.4'){ // excluding org.json which is provided by Android exclude group: 'io.netty' exclude group: 'com.google.protobuf' exclude group: 'org.apache.commons.math' } - implementation (group: 'com.shimmerresearch', name: 'shimmerdriver', version:'0.10.0_alpha'){ + implementation (group: 'com.shimmerresearch', name: 'shimmerdriverdev', version:'JA-90_v0.4'){ // excluding org.json which is provided by Android exclude group: 'io.netty' exclude group: 'com.google.protobuf' diff --git a/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/android/guiUtilities/ShimmerDialogConfigurations.java b/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/android/guiUtilities/ShimmerDialogConfigurations.java index aa61f796..631571df 100644 --- a/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/android/guiUtilities/ShimmerDialogConfigurations.java +++ b/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/android/guiUtilities/ShimmerDialogConfigurations.java @@ -29,6 +29,7 @@ import com.shimmerresearch.android.manager.ShimmerBluetoothManagerAndroid; import com.shimmerresearch.android.shimmerService.ShimmerService; import com.shimmerresearch.androidinstrumentdriver.R; +import com.shimmerresearch.androidradiodriver.Shimmer3BLEAndroid; import com.shimmerresearch.bluetooth.ShimmerBluetooth; import com.shimmerresearch.driver.Configuration; import com.shimmerresearch.driver.ShimmerDevice; @@ -224,6 +225,8 @@ public void onClick(DialogInterface dialog, int id) { if (shimmerDeviceClone instanceof Shimmer) { bluetoothManager.configureShimmer(shimmerDeviceClone); + }else if(shimmerDeviceClone instanceof Shimmer3BLEAndroid) { + bluetoothManager.configureShimmer(shimmerDeviceClone); } } }) @@ -329,6 +332,8 @@ public void onClick(DialogInterface dialog, int which) { ((Shimmer)shimmerDevice).writeConfigBytes(shimmerDeviceClone.getShimmerConfigBytes()); } else if (shimmerDevice instanceof Shimmer4Android){ ((Shimmer4Android)shimmerDevice).writeConfigBytes(shimmerDeviceClone.getShimmerConfigBytes()); + }else if(shimmerDeviceClone instanceof Shimmer3BLEAndroid) { + ((Shimmer3BLEAndroid)shimmerDevice).writeBytes(shimmerDeviceClone.getShimmerConfigBytes()); } } }); @@ -363,6 +368,8 @@ public void onClick(DialogInterface dialog, int which) { ((Shimmer)shimmerDevice).writeConfigBytes(shimmerDeviceClone.getShimmerConfigBytes()); } else if (shimmerDevice instanceof Shimmer4Android){ ((Shimmer4Android)shimmerDevice).writeConfigBytes(shimmerDeviceClone.getShimmerConfigBytes()); + }else if(shimmerDeviceClone instanceof Shimmer3BLEAndroid) { + ((Shimmer3BLEAndroid)shimmerDevice).writeBytes(shimmerDeviceClone.getShimmerConfigBytes()); } } }); @@ -415,6 +422,8 @@ public void onClick(DialogInterface dialog, int which) { //((Shimmer)shimmerDevice).configureShimmer(shimmerDeviceClone); } else if (shimmerDevice instanceof Shimmer4Android){ bluetoothManager.configureShimmer(shimmerDeviceClone); + }else if(shimmerDevice instanceof Shimmer3BLEAndroid) { + bluetoothManager.configureShimmer(shimmerDeviceClone); } } }); @@ -532,6 +541,8 @@ public void writeConfigToShimmer(ShimmerDevice clone, ShimmerBluetoothManagerAnd bluetoothManager.configureShimmer(clone); } else if (clone instanceof Shimmer4Android){ bluetoothManager.configureShimmer(clone); + } else if (clone instanceof Shimmer3BLEAndroid){ + bluetoothManager.configureShimmer(clone); } } diff --git a/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/android/manager/ShimmerBluetoothManagerAndroid.java b/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/android/manager/ShimmerBluetoothManagerAndroid.java index 783b172b..ad4f5e58 100644 --- a/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/android/manager/ShimmerBluetoothManagerAndroid.java +++ b/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/android/manager/ShimmerBluetoothManagerAndroid.java @@ -4,8 +4,14 @@ import android.app.ProgressDialog; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.ScanCallback; +import android.bluetooth.le.ScanFilter; +import android.bluetooth.le.ScanResult; +import android.bluetooth.le.ScanSettings; import android.content.Context; import android.os.Handler; +import android.os.ParcelUuid; import android.util.Log; import android.widget.Toast; @@ -13,6 +19,7 @@ import com.shimmerresearch.android.Shimmer4Android; import com.shimmerresearch.android.VerisenseDeviceAndroid; import com.shimmerresearch.androidradiodriver.AndroidBleRadioByteCommunication; +import com.shimmerresearch.androidradiodriver.Shimmer3BLEAndroid; import com.shimmerresearch.androidradiodriver.ShimmerRadioInitializerAndroid; import com.shimmerresearch.androidradiodriver.ShimmerSerialPortAndroid; import com.shimmerresearch.bluetooth.ShimmerBluetooth; @@ -62,6 +69,11 @@ public class ShimmerBluetoothManagerAndroid extends ShimmerBluetoothManager { protected Handler mHandler; private boolean AllowAutoPairing = true; + public enum BT_TYPE{ + BT_CLASSIC, + BLE + } + public ShimmerBluetoothManagerAndroid(Context context, Handler handler) throws Exception { super(); ShimmerRadioInitializer.useLegacyDelayBeforeBtRead(true); @@ -167,11 +179,107 @@ public void run(){ thread.start(); } + public void connectShimmerThroughBTAddress(final String bluetoothAddress, BT_TYPE btType) { + if(btType.equals(BT_TYPE.BT_CLASSIC)){ + connectShimmerThroughBTAddress(bluetoothAddress); + }else{ + connectShimmer3BLEThroughBTAddress(bluetoothAddress,"",null); + } + } @Override public void connectShimmerThroughBTAddress(final String bluetoothAddress) { + + //scanLeDevice(bluetoothAddress); + //doDiscovery(); connectShimmerThroughBTAddress(bluetoothAddress,"",null); } + public void connectShimmer3BLEThroughBTAddress(final String bluetoothAddress, final String deviceName, Context context){ + final Shimmer3BLEAndroid shimmer3BLE = new Shimmer3BLEAndroid(bluetoothAddress, mHandler); + shimmer3BLE.setMacIdFromUart(bluetoothAddress); + initializeNewShimmerCommon(shimmer3BLE); + Thread thread = new Thread(){ + public void run(){ + shimmer3BLE.connect(bluetoothAddress, "default"); + } + }; + thread.start(); + } + + //BT Classic Scan + private void doDiscovery() { + + // If we're already discovering, stop it + if (mBluetoothAdapter.isDiscovering()) { + mBluetoothAdapter.cancelDiscovery(); + } + + // Request discover from BluetoothAdapter + mBluetoothAdapter.startDiscovery(); + } + + private BluetoothLeScanner bluetoothLeScanner; + private boolean scanning; + private Handler handler = new Handler(); + // Stops scanning after 10 seconds. + private static final long SCAN_PERIOD = 10000; + List listScanBleDevice = new ArrayList(); + + //BLE Scan + private void scanLeDevice(String deviceMacAddress) { + getScannedBleDevices(); + bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner(); + if (!scanning) { + // Stops scanning after a predefined scan period. + handler.postDelayed(new Runnable() { + @Override + public void run() { + scanning = false; + bluetoothLeScanner.stopScan(leScanCallback); + } + }, SCAN_PERIOD); + + scanning = true; + scanForAllBleDevices(); + //scanForSpecificBleDevices(deviceMacAddress); + + } else { + scanning = false; + bluetoothLeScanner.stopScan(leScanCallback); + } + } + private void scanForAllBleDevices() { + bluetoothLeScanner.startScan(leScanCallback); + } + private void scanForSpecificBleDevices(String deviceMacAddress) { + List scanFilters = new ArrayList<>(); + ScanFilter filter = new ScanFilter.Builder().setDeviceAddress(deviceMacAddress).build(); + scanFilters.add(filter); + ScanSettings scanSettings = new ScanSettings.Builder().build(); + bluetoothLeScanner.startScan(scanFilters, scanSettings, leScanCallback); + } + + // Device scan callback. + private ScanCallback leScanCallback = + new ScanCallback() { + @Override + public void onScanResult(int callbackType, ScanResult result) { + super.onScanResult(callbackType, result); + BluetoothDevice bledevice = result.getDevice(); + if(!listScanBleDevice.contains(result.getDevice())){ + listScanBleDevice.add(result.getDevice()); + } + } + }; + + private void getScannedBleDevices(){ + for(BluetoothDevice dev : listScanBleDevice) + { + System.out.println(dev.getAddress()); + } + + } + private boolean isDevicePaired(String bluetoothAddress){ Set pairedDevices = mBluetoothAdapter.getBondedDevices(); for(BluetoothDevice device: pairedDevices){ diff --git a/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/androidradiodriver/AndroidBleRadioByteCommunication.java b/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/androidradiodriver/AndroidBleRadioByteCommunication.java index b1948790..472c3171 100644 --- a/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/androidradiodriver/AndroidBleRadioByteCommunication.java +++ b/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/androidradiodriver/AndroidBleRadioByteCommunication.java @@ -1,5 +1,6 @@ package com.shimmerresearch.androidradiodriver; +import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattService; @@ -94,6 +95,9 @@ public void onMtuChanged(int mtu) { } catch (InterruptedException e) { e.printStackTrace(); } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH); + } if (mByteCommunicationListener != null) { mByteCommunicationListener.eventConnected(); @@ -101,6 +105,9 @@ public void onMtuChanged(int mtu) { mBleDevice = bleDevice; startServiceS(bleDevice); System.out.println(bleDevice.getMac() + " Connected"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + gatt.setPreferredPhy(BluetoothDevice.PHY_LE_2M_MASK, BluetoothDevice.PHY_LE_2M_MASK, BluetoothDevice.PHY_OPTION_NO_PREFERRED); + } mTaskConnect.setResult("Connected"); } @@ -181,7 +188,11 @@ public void onNotifyFailure(BleException exception) { @Override public void onCharacteristicChanged(byte[] data) { if (mByteCommunicationListener != null) { - mByteCommunicationListener.eventNewBytesReceived(data); + try{ + mByteCommunicationListener.eventNewBytesReceived(data); + }catch (Exception e){ + e.printStackTrace(); + } } } }); diff --git a/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/androidradiodriver/Shimmer3BLEAndroid.java b/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/androidradiodriver/Shimmer3BLEAndroid.java new file mode 100644 index 00000000..2785d85d --- /dev/null +++ b/ShimmerAndroidInstrumentDriver/ShimmerAndroidInstrumentDriver/src/main/java/com/shimmerresearch/androidradiodriver/Shimmer3BLEAndroid.java @@ -0,0 +1,602 @@ +package com.shimmerresearch.androidradiodriver; + +import static com.shimmerresearch.android.Shimmer.MESSAGE_TOAST; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattService; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; + +import com.clj.fastble.BleManager; +import com.clj.fastble.callback.BleGattCallback; +import com.clj.fastble.callback.BleMtuChangedCallback; +import com.clj.fastble.callback.BleNotifyCallback; +import com.clj.fastble.callback.BleWriteCallback; +import com.clj.fastble.data.BleDevice; +import com.clj.fastble.exception.BleException; +import com.shimmerresearch.android.Shimmer; +import com.shimmerresearch.bluetooth.BluetoothProgressReportPerCmd; +import com.shimmerresearch.bluetooth.ShimmerBluetooth; +import com.shimmerresearch.driver.BasicProcessWithCallBack; +import com.shimmerresearch.driver.CallbackObject; +import com.shimmerresearch.driver.Configuration; +import com.shimmerresearch.driver.FormatCluster; +import com.shimmerresearch.driver.ObjectCluster; +import com.shimmerresearch.driver.ShimmerDevice; +import com.shimmerresearch.driver.ShimmerDeviceCallbackAdapter; +import com.shimmerresearch.driver.ShimmerMsg; +import com.shimmerresearch.driver.ThreadSafeByteFifoBuffer; +import com.shimmerresearch.driver.shimmer2r3.ConfigByteLayoutShimmer3; +import com.shimmerresearch.driverUtilities.ChannelDetails; +import com.shimmerresearch.driverUtilities.SensorDetails; +import com.shimmerresearch.driverUtilities.UtilShimmer; +import com.shimmerresearch.exceptions.ShimmerException; +import com.shimmerresearch.sensors.kionix.SensorKionixAccel; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import bolts.TaskCompletionSource; + +public class Shimmer3BLEAndroid extends ShimmerBluetooth implements Serializable { + transient BleDevice mBleDevice; + String TxID = "49535343-8841-43f4-a8d4-ecbe34729bb3"; + String RxID = "49535343-1e4d-4bd9-ba61-23c647249616"; + String ServiceID = "49535343-fe7d-4ae5-8fa9-9fafd205e455"; + UUID sid = UUID.fromString(ServiceID); + UUID txid = UUID.fromString(TxID); + UUID rxid = UUID.fromString(RxID); + String mMac; + String uuid; + transient ThreadSafeByteFifoBuffer mBuffer; + protected transient ShimmerDeviceCallbackAdapter mDeviceCallbackAdapter = new ShimmerDeviceCallbackAdapter(this); + transient public final Handler mHandler; + public static final String TOAST = "toast"; + + //"DA:A6:19:F0:4A:D7" + //"E7:45:2C:6D:6F:14" + + /** + * Initialize a ble radio + * + * @param mac mac address of the Shimmer3 BLE device e.g. d0:2b:46:3d:a2:bb + */ + public Shimmer3BLEAndroid(String mac) { + mMac = mac; + mHandler = null; + } + + public Shimmer3BLEAndroid(String mac, Handler handler){ + mMac = mac; + mHandler = handler; + } + transient TaskCompletionSource mTaskConnect = new TaskCompletionSource<>(); + transient TaskCompletionSource mTaskMTU = new TaskCompletionSource<>(); + + @Override + public void sendCallBackMsg(int msgid,Object obj){ + if (mHandler != null) { + mHandler.obtainMessage(msgid, obj).sendToTarget(); + } + } + /** + * Connect to the Shimmer3 BLE device + */ + @Override + public void connect(String s, String s1) { + mTaskConnect = new TaskCompletionSource<>(); + BleManager.getInstance().connect(mMac, new BleGattCallback() { + @Override + public void onStartConnect() { + System.out.println("Connecting"); + } + + @Override + public void onConnectFail(BleDevice bleDevice, BleException exception) { + + } + + @Override + public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) { + mBuffer = new ThreadSafeByteFifoBuffer(1000000); + mTaskMTU = new TaskCompletionSource<>(); + BleManager.getInstance().setMtu(bleDevice, 251, new BleMtuChangedCallback() { + @Override + public void onSetMTUFailure(BleException exception) { + System.out.println("MTU Failure"); + + } + + @Override + public void onMtuChanged(int mtu) { + System.out.println("MTU Changed: " + mtu); + mTaskMTU.setResult("MTU Changed: " + mtu); + } + }); + + try { + boolean result = mTaskMTU.getTask().waitForCompletion(3, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH); + } + + mBleDevice = bleDevice; + startServiceS(bleDevice); + System.out.println(bleDevice.getMac() + " Connected"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + gatt.setPreferredPhy(BluetoothDevice.PHY_LE_2M_MASK, BluetoothDevice.PHY_LE_2M_MASK, BluetoothDevice.PHY_OPTION_NO_PREFERRED); + } + mTaskConnect.setResult("Connected"); + //mHandler.obtainMessage(ShimmerBluetooth.MSG_IDENTIFIER_STATE_CHANGE, -1, -1, + //new ObjectCluster("", bleDevice.getMac(), BT_STATE.CONNECTED)).sendToTarget(); + sendCallBackMsg(ShimmerBluetooth.MSG_IDENTIFIER_STATE_CHANGE, new ObjectCluster("", bleDevice.getMac(), BT_STATE.CONNECTED)); + Bundle bundle = new Bundle(); + bundle.putString(TOAST, "Device connection established"); + sendMsgToHandlerList(MESSAGE_TOAST, bundle); + + mIOThread = new IOThread(); + mIOThread.start(); + if (mUseProcessingThread){ + mPThread = new ProcessingThread(); + mPThread.start(); + } + + initialize(); + } + + @Override + public void onDisConnected(boolean isActiveDisConnected, BleDevice bleDevice, BluetoothGatt gatt, int status) { + //mHandler.obtainMessage(ShimmerBluetooth.MSG_IDENTIFIER_STATE_CHANGE, -1, -1, + //new ObjectCluster("", bleDevice.getMac(), BT_STATE.DISCONNECTED)).sendToTarget(); + sendCallBackMsg(ShimmerBluetooth.MSG_IDENTIFIER_STATE_CHANGE, new ObjectCluster("", bleDevice.getMac(), BT_STATE.DISCONNECTED)); + + Bundle bundle = new Bundle(); + bundle.putString(TOAST, "Device connection was lost"); + sendMsgToHandlerList(MESSAGE_TOAST, bundle); + System.out.println(); + } + }); + + + try { + boolean result = mTaskConnect.getTask().waitForCompletion(10, TimeUnit.SECONDS); + Thread.sleep(200); + if (!result) { + System.out.println("Connect fail"); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public void startServiceS(BleDevice bleDevice) { + List services = BleManager.getInstance().getBluetoothGattServices(bleDevice); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + + + for (BluetoothGattService service : services) { + System.out.println(service.getUuid()); + if (service.getUuid().compareTo(sid) == 0) { + for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) { + if (characteristic.getUuid().compareTo(txid) == 0) { + //newConnectedBLEDevice(bleDevice,characteristic); + CharSequence text = "TXID!"; + } else if (characteristic.getUuid().compareTo(rxid) == 0) { + newConnectedBLEDevice(bleDevice, characteristic); + CharSequence text = "RxID!"; + } + } + } + } + + + } + } + + /** + * Start notify for characteristics changed + * + * @param bleDevice BLE device + * @param characteristic + */ + public void newConnectedBLEDevice(final BleDevice bleDevice, final BluetoothGattCharacteristic characteristic) { + int count = 1; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + BleManager.getInstance().notify( + bleDevice, + characteristic.getService().getUuid().toString(), + characteristic.getUuid().toString(), + new BleNotifyCallback() { + + + @Override + public void onNotifySuccess() { + + } + + @Override + public void onNotifyFailure(BleException exception) { + + } + + @Override + public void onCharacteristicChanged(byte[] data) { + try { + mBuffer.write(data); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + }); + } + } + + @Override + protected boolean bytesAvailableToBeRead() { + if (mBuffer.size()>0) { + return true; + } + return false; + } + + @Override + protected int availableBytes() { + return mBuffer.size(); + } + + @Override + public void writeBytes(byte[] bytes) { + BleManager.getInstance().write(mBleDevice, sid.toString(), txid.toString(), bytes, false, new BleWriteCallback() { + @Override + public void onWriteSuccess(int current, int total, byte[] justWrite) { + System.out.println("Write Success " + UtilShimmer.bytesToHexStringWithSpacesFormatted(justWrite)); + } + + @Override + public void onWriteFailure(BleException exception) { + System.out.println("Write Fail"); + } + }); + } + + @Override + protected void stop() { + try { + disconnect(); + } catch (ShimmerException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + protected void sendProgressReport(BluetoothProgressReportPerCmd bluetoothProgressReportPerCmd) { + mDeviceCallbackAdapter.sendProgressReport(bluetoothProgressReportPerCmd); + } + + @Override + protected void isReadyForStreaming() { + mDeviceCallbackAdapter.isReadyForStreaming(); + restartTimersIfNull(); + } + + @Override + protected void isNowStreaming() { + mDeviceCallbackAdapter.isNowStreaming(); + } + + @Override + protected void hasStopStreaming() { + mDeviceCallbackAdapter.hasStopStreaming(); + } + + @Override + protected void sendStatusMsgPacketLossDetected() { + + } + + @Override + protected void inquiryDone() { + mDeviceCallbackAdapter.inquiryDone(); + isReadyForStreaming(); + } + + @Override + protected void sendStatusMSGtoUI(String s) { + + } + + @Override + protected void printLogDataForDebugging(String s) { + consolePrintLn(s); + } + + @Override + protected void connectionLost() { + try { + disconnect(); + } catch (ShimmerException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + setBluetoothRadioState(BT_STATE.CONNECTION_LOST); + } + + @Override + public boolean setBluetoothRadioState(BT_STATE state) { + boolean isChanged = super.setBluetoothRadioState(state); + mDeviceCallbackAdapter.setBluetoothRadioState(state, isChanged); + return isChanged; + } + + @Override + protected void startOperation(BT_STATE bt_state) { + this.startOperation(bt_state, 1); + consolePrintLn(bt_state + " START"); + } + + @Override + protected void finishOperation(BT_STATE bt_state) { + mDeviceCallbackAdapter.finishOperation(bt_state); + } + + @Override + protected void startOperation(BT_STATE bt_state, int i) { + mDeviceCallbackAdapter.startOperation(bt_state, i); + } + + @Override + protected void eventLogAndStreamStatusChanged(byte currentCommand) { + if (currentCommand == STOP_LOGGING_ONLY_COMMAND) { + //TODO need to query the Bluetooth connection here! + if (mIsStreaming) { + setBluetoothRadioState(BT_STATE.STREAMING); + } else if (isConnected()) { + setBluetoothRadioState(BT_STATE.CONNECTED); + } else { + setBluetoothRadioState(BT_STATE.DISCONNECTED); + } + } else { + if (mIsStreaming && isSDLogging()) { + setBluetoothRadioState(BT_STATE.STREAMING_AND_SDLOGGING); + } else if (mIsStreaming) { + setBluetoothRadioState(BT_STATE.STREAMING); + } else if (isSDLogging()) { + setBluetoothRadioState(BT_STATE.SDLOGGING); + } else { + // if(!isStreaming() && !isSDLogging() && isConnected()){ + if (!mIsStreaming && !isSDLogging() && isConnected() && mBluetoothRadioState != BT_STATE.CONNECTED) { + setBluetoothRadioState(BT_STATE.CONNECTED); + } + // if(getBTState() == BT_STATE.INITIALISED){ + // + // } + // else if(getBTState() != BT_STATE.CONNECTED){ + // setState(BT_STATE.CONNECTED); + // } + + CallbackObject callBackObject = new CallbackObject(NOTIFICATION_SHIMMER_STATE_CHANGE, mBluetoothRadioState, getMacId(), getComPort()); + sendCallBackMsg(MSG_IDENTIFIER_STATE_CHANGE, callBackObject); + } + } + } + + @Override + protected void batteryStatusChanged() { + mDeviceCallbackAdapter.batteryStatusChanged(); + } + + @Override + protected byte[] readBytes(int numberofBytes) { + try { + return mBuffer.read(numberofBytes); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + @Override + protected byte readByte() { + try { + return mBuffer.read(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return -1; + } + + @Override + protected void dockedStateChange() { + mDeviceCallbackAdapter.dockedStateChange(); + } + + @Override + public ShimmerDevice deepClone() { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(this); + + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + Object readdd = ois.readObject(); + return (ShimmerDevice) readdd; + } catch (IOException e) { + e.printStackTrace(); + return null; + } catch (ClassNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + @Override + protected void interpretDataPacketFormat(Object o, Configuration.COMMUNICATION_TYPE communication_type) { + + } + + @Override + public void createConfigBytesLayout() { + mConfigByteLayout = new ConfigByteLayoutShimmer3(getFirmwareIdentifier(), getFirmwareVersionMajor(), getFirmwareVersionMinor(), getFirmwareVersionInternal()); + } + + @Override + protected void dataHandler(ObjectCluster objectCluster) { + mDeviceCallbackAdapter.dataHandler(objectCluster); + } + + @Override + protected void processMsgFromCallback(ShimmerMsg shimmerMsg) { + System.out.println(shimmerMsg.mIdentifier); + } + + @Override + public void disconnect() throws ShimmerException { + // super.disconnect(); + stopAllTimers(); + BleManager.getInstance().disconnect(mBleDevice); + closeConnection(); + setBluetoothRadioState(BT_STATE.DISCONNECTED); + Bundle bundle = new Bundle(); + bundle.putString(TOAST, "Device connection was lost"); + sendMsgToHandlerList(MESSAGE_TOAST, bundle); + } + private void sendMsgToHandlerList(int obtainMessage, Bundle bundle) { + if (mHandler != null) { + Message msg = mHandler.obtainMessage(obtainMessage); + msg.setData(bundle); + mHandler.sendMessage(msg); + } + + } + private void closeConnection() { + try { + if (mIOThread != null) { + mIOThread.stop = true; + + // Closing serial port before before thread is finished stopping throws an error so waiting here + while (mIOThread != null && mIOThread.isAlive()) ; + + mIOThread = null; + + if (mUseProcessingThread) { + mPThread.stop = true; + mPThread = null; + } + } + mIsStreaming = false; + mIsInitialised = false; + + setBluetoothRadioState(BT_STATE.DISCONNECTED); + } catch (Exception ex) { + consolePrintException(ex.getMessage(), ex.getStackTrace()); + setBluetoothRadioState(BT_STATE.DISCONNECTED); + } + } + + //Need to override here because ShimmerDevice class uses a different map + @Override + public String getSensorLabel(int sensorKey) { + //TODO 2017-08-03 MN: super does this but in a different way, don't know is either is better + super.getSensorLabel(sensorKey); + SensorDetails sensor = mSensorMap.get(sensorKey); + if (sensor != null) { + return sensor.mSensorDetailsRef.mGuiFriendlyLabel; + } + return null; + } + + public class SensorDataReceived extends BasicProcessWithCallBack { + + @Override + protected void processMsgFromCallback(ShimmerMsg shimmerMSG) { + // TODO Auto-generated method stub + System.out.println(shimmerMSG.mIdentifier); + + + // TODO Auto-generated method stub + + // TODO Auto-generated method stub + int ind = shimmerMSG.mIdentifier; + + Object object = (Object) shimmerMSG.mB; + + if (ind == Shimmer.MSG_IDENTIFIER_STATE_CHANGE) { + CallbackObject callbackObject = (CallbackObject) object; + + if (callbackObject.mState == BT_STATE.CONNECTING) { + } else if (callbackObject.mState == BT_STATE.CONNECTED) { + } else if (callbackObject.mState == BT_STATE.DISCONNECTED + // || callbackObject.mState == BT_STATE.NONE + || callbackObject.mState == BT_STATE.CONNECTION_LOST) { + + } + } else if (ind == Shimmer.MSG_IDENTIFIER_NOTIFICATION_MESSAGE) { + CallbackObject callbackObject = (CallbackObject) object; + int msg = callbackObject.mIndicator; + if (msg == Shimmer.NOTIFICATION_SHIMMER_FULLY_INITIALIZED) { + } + if (msg == Shimmer.NOTIFICATION_SHIMMER_STOP_STREAMING) { + + } else if (msg == Shimmer.NOTIFICATION_SHIMMER_START_STREAMING) { + + } else { + } + } else if (ind == Shimmer.MSG_IDENTIFIER_DATA_PACKET) { + + double accelX = 0; + double accelY = 0; + double accelZ = 0; + FormatCluster formatx; + FormatCluster formaty; + FormatCluster formatz; + + int INVALID_RESULT = -1; + + ObjectCluster objc = (ObjectCluster) shimmerMSG.mB; + + Collection adcFormats = objc.getCollectionOfFormatClusters(SensorKionixAccel.ObjectClusterSensorName.ACCEL_LN_X); + formatx = ((FormatCluster) ObjectCluster.returnFormatCluster(adcFormats, ChannelDetails.CHANNEL_TYPE.CAL.toString())); // retrieve the calibrated data + + adcFormats = objc.getCollectionOfFormatClusters(SensorKionixAccel.ObjectClusterSensorName.ACCEL_LN_Y); + formaty = ((FormatCluster) ObjectCluster.returnFormatCluster(adcFormats, ChannelDetails.CHANNEL_TYPE.CAL.toString())); // retrieve the calibrated data + + adcFormats = objc.getCollectionOfFormatClusters(SensorKionixAccel.ObjectClusterSensorName.ACCEL_LN_Z); + formatz = ((FormatCluster) ObjectCluster.returnFormatCluster(adcFormats, ChannelDetails.CHANNEL_TYPE.CAL.toString())); // retrieve the calibrated data + + if (formatx != null) { + System.out.println("X:" + formatx.mData + " Y:" + formaty.mData + " Z:" + formatz.mData); + + } else { + System.out.println("ERROR! FormatCluster is Null!"); + } + + } else if (ind == Shimmer.MSG_IDENTIFIER_PACKET_RECEPTION_RATE_OVERALL) { + + } + + + } + + } +} diff --git a/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/README.md b/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/README.md index a42194bc..ede7f932 100644 --- a/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/README.md +++ b/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/README.md @@ -1,5 +1,6 @@ # Bluetooth Manager Example This example is only applicable for Shimmer3 devices onwards -- This example automatically connects to a shimmer device (see variable shimmerBtAdd in MainActivity), otherwise the connect button can be used to connect to a single shimmer device +- Allow all requested permissions and make sure Bluetooth is enabled +- Use the CONNECT button to start, select Paired Devices from the list or Scan for Devices, choose either to use BLE or BT CLASSIC connection from the popup dialog - Low Noise Accelerometer and Timestamp data are printed to the logcat when streaming, note there won't be low noise accelerometer data if the sensor is not enabled diff --git a/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/build.gradle b/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/build.gradle index 0a3f61db..b9d0d02a 100644 --- a/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/build.gradle +++ b/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/build.gradle @@ -1,13 +1,18 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 + compileSdkVersion 31 + + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } defaultConfig { multiDexEnabled true applicationId "com.shimmerresearch.bluetoothmanagerexample" minSdkVersion 14 - targetSdkVersion 25 + targetSdkVersion 31 versionCode 1 versionName "1.0" @@ -44,13 +49,13 @@ android { dependencies { compile project(':ShimmerAndroidInstrumentDriver') - implementation (group: 'com.shimmersensing', name: 'ShimmerBluetoothManagerDev', version:'vcba-47 v0.2'){ + implementation (group: 'com.shimmerresearch', name: 'shimmerbluetoothmanagerdev', version:'JA-90_v0.4'){ // excluding org.json which is provided by Android exclude group: 'io.netty' exclude group: 'com.google.protobuf' exclude group: 'org.apache.commons.math' } - implementation (group: 'com.shimmersensing', name: 'ShimmerDriverDev', version:'vcba-47 v0.2'){ + implementation (group: 'com.shimmerresearch', name: 'shimmerdriverdev', version:'JA-90_v0.4'){ // excluding org.json which is provided by Android exclude group: 'io.netty' exclude group: 'com.google.protobuf' diff --git a/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/src/main/AndroidManifest.xml b/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/src/main/AndroidManifest.xml index c9a9c49f..bbebb700 100644 --- a/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/src/main/AndroidManifest.xml +++ b/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/src/main/AndroidManifest.xml @@ -1,12 +1,19 @@ - + + + + + + + - + diff --git a/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/src/main/java/com/shimmerresearch/bluetoothmanagerexample/MainActivity.java b/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/src/main/java/com/shimmerresearch/bluetoothmanagerexample/MainActivity.java index ce3867f8..afe570be 100644 --- a/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/src/main/java/com/shimmerresearch/bluetoothmanagerexample/MainActivity.java +++ b/ShimmerAndroidInstrumentDriver/bluetoothManagerExample/src/main/java/com/shimmerresearch/bluetoothmanagerexample/MainActivity.java @@ -1,9 +1,22 @@ package com.shimmerresearch.bluetoothmanagerexample; +import android.Manifest; import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.os.Build; import android.os.Handler; +import android.os.Looper; import android.os.Message; +import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; @@ -11,6 +24,7 @@ import android.widget.TextView; import android.widget.Toast; +import com.clj.fastble.BleManager; import com.shimmerresearch.android.Shimmer; import com.shimmerresearch.android.guiUtilities.ShimmerBluetoothDialog; import com.shimmerresearch.android.guiUtilities.ShimmerDialogConfigurations; @@ -21,6 +35,7 @@ import com.shimmerresearch.driver.FormatCluster; import com.shimmerresearch.driver.ObjectCluster; import com.shimmerresearch.driver.ShimmerDevice; +import com.shimmerresearch.exceptions.ShimmerException; import java.io.IOException; import java.util.Collection; @@ -40,8 +55,9 @@ public class MainActivity extends AppCompatActivity { ShimmerBluetoothManagerAndroid btManager; ShimmerDevice shimmerDevice; - String shimmerBtAdd = "00:00:00:00:00:00"; //Put the address of the Shimmer device you want to connect here + String shimmerBtAdd; + ShimmerBluetoothManagerAndroid.BT_TYPE preferredBtType; final static String LOG_TAG = "BluetoothManagerExample"; TextView textView; @@ -49,17 +65,80 @@ public class MainActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + requestPermissions(new String[]{ + Manifest.permission.BLUETOOTH_ADVERTISE, + Manifest.permission.BLUETOOTH_CONNECT, + Manifest.permission.BLUETOOTH_SCAN, + Manifest.permission.ACCESS_FINE_LOCATION}, + 0); + }else{ + requestPermissions(new String[]{ + Manifest.permission.ACCESS_FINE_LOCATION}, + 0); + } + } - try { - btManager = new ShimmerBluetoothManagerAndroid(this, mHandler); - } catch (Exception e) { - Log.e(LOG_TAG, "Couldn't create ShimmerBluetoothManagerAndroid. Error: " + e); +// Register for broadcasts when a device is discovered. + IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); + registerReceiver(receiver, filter); + } + + // Create a BroadcastReceiver for ACTION_FOUND. + private final BroadcastReceiver receiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (BluetoothDevice.ACTION_FOUND.equals(action)) { + // Discovery has found a device. Get the BluetoothDevice + // object and its info from the Intent. + BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { + return; + } + } + String deviceName = device.getName(); + String deviceHardwareAddress = device.getAddress(); // MAC address + } } + }; + @Override + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + boolean allPermissionsGranted = true; + for (int result : grantResults){ + if(result != 0){ + allPermissionsGranted = false; + } + } + if(!allPermissionsGranted){ + Toast.makeText(this, "Please allow all requested permissions", Toast.LENGTH_SHORT).show(); + }else{ + BleManager.getInstance().init(getApplication()); + try { + btManager = new ShimmerBluetoothManagerAndroid(this, mHandler); + } catch (Exception e) { + Log.e(LOG_TAG, "Couldn't create ShimmerBluetoothManagerAndroid. Error: " + e); + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { + return; + } + startActivityForResult(enableBtIntent, 1); + } + } + } + @Override + protected void onDestroy() { + super.onDestroy(); + // Don't forget to unregister the ACTION_FOUND receiver. + unregisterReceiver(receiver); } @Override protected void onStart() { + /* //Connect the Shimmer using its Bluetooth Address try { btManager.connectShimmerThroughBTAddress(shimmerBtAdd); @@ -67,7 +146,7 @@ protected void onStart() { Log.e(LOG_TAG, "Error. Shimmer device not paired or Bluetooth is not enabled"); Toast.makeText(this, "Error. Shimmer device not paired or Bluetooth is not enabled. " + "Please close the app and pair or enable Bluetooth", Toast.LENGTH_LONG).show(); - } + }*/ textView = (TextView) findViewById(R.id.textView); super.onStart(); } @@ -81,7 +160,11 @@ protected void onStop() { Log.d(LOG_TAG, "Stopped Shimmer Logging"); } else if(shimmerDevice.isStreaming()) { - shimmerDevice.stopStreaming(); + try { + shimmerDevice.stopStreaming(); + } catch (ShimmerException e) { + e.printStackTrace(); + } Log.d(LOG_TAG, "Stopped Shimmer Streaming"); } else { @@ -165,6 +248,7 @@ public void handleMessage(Message msg) { break; case DISCONNECTED: Log.i(LOG_TAG, "Shimmer [" + macAddress + "] has been DISCONNECTED"); + shimmerDevice = null; break; } break; @@ -175,11 +259,19 @@ public void handleMessage(Message msg) { }; public void stopStreaming(View v){ - shimmerDevice.stopStreaming(); + try { + shimmerDevice.stopStreaming(); + } catch (ShimmerException e) { + e.printStackTrace(); + } } public void startStreaming(View v){ - shimmerDevice.startStreaming(); + try { + shimmerDevice.startStreaming(); + } catch (ShimmerException e) { + e.printStackTrace(); + } } /** @@ -254,15 +346,44 @@ public void stopSDLogging(View v) { protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == 2) { if (resultCode == Activity.RESULT_OK) { + if(btManager==null){ + try { + btManager = new ShimmerBluetoothManagerAndroid(this, mHandler); + } catch (Exception e) { + Log.e(LOG_TAG, "Couldn't create ShimmerBluetoothManagerAndroid. Error: " + e); + } + } btManager.disconnectAllDevices(); //Disconnect all devices first shimmerDevice = null; + showBtTypeConnectionOption(); //Get the Bluetooth mac address of the selected device: String macAdd = data.getStringExtra(EXTRA_DEVICE_ADDRESS); - btManager.connectShimmerThroughBTAddress(macAdd); //Connect to the selected device + btManager.connectShimmerThroughBTAddress(macAdd, preferredBtType); //Connect to the selected device shimmerBtAdd = macAdd; } } super.onActivityResult(requestCode, resultCode, data); } -} + Looper looper = Looper.myLooper(); + + public void showBtTypeConnectionOption(){ + AlertDialog alertDialog = new AlertDialog.Builder(this).create(); + alertDialog.setCancelable(false); + alertDialog.setMessage("Choose preferred Bluetooth type"); + alertDialog.setButton( Dialog.BUTTON_POSITIVE, "BT CLASSIC", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + preferredBtType = ShimmerBluetoothManagerAndroid.BT_TYPE.BT_CLASSIC; + looper.quit(); + }; + }); + alertDialog.setButton( Dialog.BUTTON_NEGATIVE, "BLE", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + preferredBtType = ShimmerBluetoothManagerAndroid.BT_TYPE.BLE; + looper.quit(); + }; + }); + alertDialog.show(); + try{ looper.loop(); } + catch(RuntimeException e){} + }} diff --git a/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/.gitignore b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/build.gradle b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/build.gradle new file mode 100644 index 00000000..bbc10372 --- /dev/null +++ b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/build.gradle @@ -0,0 +1,73 @@ +plugins { + id 'com.android.application' +} + +android { + //buildToolsVersion '23.0.1' + compileSdkVersion 26 + + defaultConfig { + applicationId "shimmerresearch.com.multiverisenseblebasicexample" + minSdkVersion 18 + targetSdkVersion 26 + versionCode 1 + versionName "1.0" + multiDexEnabled true + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + packagingOptions { + exclude 'META-INF/DEPENDENCIES' + exclude 'META-INF/LICENSE' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/license.txt' + exclude 'META-INF/NOTICE' + exclude 'META-INF/NOTICE.txt' + exclude 'META-INF/notice.txt' + exclude 'META-INF/ASL2.0' + } + configurations.all { + resolutionStrategy.force 'com.android.support:support-annotations:25.3.1' + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(path: ':ShimmerAndroidInstrumentDriver') + + androidTestCompile 'com.android.support:support-annotations:25.3.1' + //compile(group: 'com.shimmersensing', name: 'ShimmerAndroidInstrumentDriver', version: '3.0.71Beta', ext: 'aar') + implementation (group: 'com.shimmerresearch', name: 'shimmerbluetoothmanagerdev', version:'JA-90_v0.4'){ + // excluding org.json which is provided by Android + exclude group: 'io.netty' + exclude group: 'com.google.protobuf' + exclude group: 'org.apache.commons.math' + } + implementation (group: 'com.shimmerresearch', name: 'shimmerdriverdev', version:'JA-90_v0.4'){ + // excluding org.json which is provided by Android + exclude group: 'io.netty' + exclude group: 'com.google.protobuf' + exclude group: 'org.apache.commons.math' + } + implementation 'com.android.support.constraint:constraint-layout:1.0.2' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.1' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + compile 'com.android.support:appcompat-v7:26.0.0' + compile 'com.android.support.constraint:constraint-layout:1.0.2' + compile 'com.android.support:support-v4:26.0.0' + compile 'com.android.support:recyclerview-v7:26.0.0' + testCompile 'junit:junit:4.12' + compile 'com.android.support:multidex:1.0.3' +} +repositories { + mavenCentral() +} diff --git a/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/proguard-rules.pro b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/androidTest/java/shimmerresearch/com/multiverisenseblebasicexample/ExampleInstrumentedTest.java b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/androidTest/java/shimmerresearch/com/multiverisenseblebasicexample/ExampleInstrumentedTest.java new file mode 100644 index 00000000..2294203e --- /dev/null +++ b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/androidTest/java/shimmerresearch/com/multiverisenseblebasicexample/ExampleInstrumentedTest.java @@ -0,0 +1,25 @@ +package shimmerresearch.com.multiverisenseblebasicexample; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("shimmerresearch.com.multiverisenseblebasicexample", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/AndroidManifest.xml b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/AndroidManifest.xml new file mode 100644 index 00000000..c040239e --- /dev/null +++ b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/java/shimmerresearch/com/multiverisenseblebasicexample/MainActivity.java b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/java/shimmerresearch/com/multiverisenseblebasicexample/MainActivity.java new file mode 100644 index 00000000..cc313c84 --- /dev/null +++ b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/java/shimmerresearch/com/multiverisenseblebasicexample/MainActivity.java @@ -0,0 +1,508 @@ +package shimmerresearch.com.multiverisenseblebasicexample; + +import static com.shimmerresearch.android.guiUtilities.ShimmerBluetoothDialog.EXTRA_DEVICE_ADDRESS; + +import android.app.Activity; +import android.content.Intent; +import android.os.Handler; +import android.os.Message; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import com.clj.fastble.BleManager; +import com.shimmerresearch.android.Shimmer; +import com.shimmerresearch.android.VerisenseDeviceAndroid; +import com.shimmerresearch.androidradiodriver.AndroidBleRadioByteCommunication; +import com.shimmerresearch.bluetooth.ShimmerBluetooth; +import com.shimmerresearch.driver.CallbackObject; +import com.shimmerresearch.driver.Configuration; +import com.shimmerresearch.driver.FormatCluster; +import com.shimmerresearch.driver.ObjectCluster; +import com.shimmerresearch.exceptions.ShimmerException; +import com.shimmerresearch.verisense.communication.VerisenseProtocolByteCommunication; +import com.shimmerresearch.verisense.sensors.SensorLIS2DW12; + +import java.io.IOException; +import java.util.Collection; + +public class MainActivity extends AppCompatActivity { + + private final static String LOG_TAG = "ShimmerBLEBasicExample"; + AndroidBleRadioByteCommunication radio1 = new AndroidBleRadioByteCommunication("C0:04:19:85:9A:D5"); + VerisenseProtocolByteCommunication protocol1 = new VerisenseProtocolByteCommunication(radio1); + VerisenseDeviceAndroid device1; + + AndroidBleRadioByteCommunication radio2 = new AndroidBleRadioByteCommunication("C9:61:17:53:74:02"); + VerisenseProtocolByteCommunication protocol2 = new VerisenseProtocolByteCommunication(radio2); + VerisenseDeviceAndroid device2; +//BTHLE\Dev_f2527c20d97e + AndroidBleRadioByteCommunication radio3 = new AndroidBleRadioByteCommunication("F2:52:7C:20:D9:7E"); + VerisenseProtocolByteCommunication protocol3 = new VerisenseProtocolByteCommunication(radio3); + VerisenseDeviceAndroid device3; + TextView txtViewThroughput1; + TextView txtViewThroughput2; + TextView txtViewThroughput3; + boolean isSpeedTestSensor1 = false; + boolean isSpeedTestSensor2 = false; + boolean isSpeedTestSensor3 = false; + private Thread t1 = null; + private Thread t2 = null; + private Thread t3 = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + BleManager.getInstance().init(getApplication()); + device1 = new VerisenseDeviceAndroid(mHandler); + device2 = new VerisenseDeviceAndroid(mHandler); + device3 = new VerisenseDeviceAndroid(mHandler); + } + + //Sensor 1 + public void connectDevice1(View v) { + + Thread thread = new Thread(){ + public void run(){ + + device1.setProtocol(Configuration.COMMUNICATION_TYPE.BLUETOOTH, protocol1); + try { + device1.connect(); + } catch (ShimmerException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + } + }; + + thread.start(); + } + + public void disconnectDevice1(View v) { + Thread thread = new Thread(){ + public void run(){ + try { + isSpeedTestSensor1 = false; + device1.disconnect(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void readOpConfig1(View v) { + Thread thread = new Thread(){ + public void run(){ + try { + protocol1.readOperationalConfig(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void readProdConfig1(View v) { + Thread thread = new Thread(){ + public void run(){ + try { + protocol1.readProductionConfig(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void startStreaming1(View v) throws InterruptedException, IOException, ShimmerException { + Thread thread = new Thread(){ + public void run(){ + try { + protocol1.startStreaming(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void stopStreaming1(View v) throws IOException, ShimmerException { + Thread thread = new Thread(){ + public void run(){ + try { + protocol1.stopStreaming(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + public void startSpeedTest1(View v) throws IOException, ShimmerException { + Thread thread = new Thread(){ + public void run(){ + try { + protocol1.startSpeedTest(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + public void stopSpeedTest1(View v) throws IOException, ShimmerException { + Thread thread = new Thread(){ + public void run(){ + try { + protocol1.stopSpeedTest(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + //Sensor 2 + public void connectDevice2(View v) { + + Thread thread = new Thread(){ + public void run(){ + + device2.setProtocol(Configuration.COMMUNICATION_TYPE.BLUETOOTH, protocol2); + try { + device2.connect(); + } catch (ShimmerException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + } + }; + + thread.start(); + } + + public void disconnectDevice2(View v) { + Thread thread = new Thread(){ + public void run(){ + try { + isSpeedTestSensor2 = false; + device2.disconnect(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void readOpConfig2(View v) { + Thread thread = new Thread(){ + public void run(){ + try { + protocol2.readOperationalConfig(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void readProdConfig2(View v) { + Thread thread = new Thread(){ + public void run(){ + try { + protocol2.readProductionConfig(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void startStreaming2(View v) throws InterruptedException, IOException, ShimmerException { + Thread thread = new Thread(){ + public void run(){ + try { + protocol2.startStreaming(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void stopStreaming2(View v) throws IOException, ShimmerException { + Thread thread = new Thread(){ + public void run(){ + try { + protocol2.stopStreaming(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + public void startSpeedTest1And2(View v) throws IOException, ShimmerException { + t1 = new Thread(new Runnable() { + @Override + public void run() { + try { + protocol1.startSpeedTest(); + protocol2.startSpeedTest(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }); + t1.start(); + } + public void stopSpeedTest1And2(View v) throws IOException, ShimmerException { + Thread thread = new Thread(){ + public void run(){ + try { + protocol1.stopSpeedTest(); + protocol2.stopSpeedTest(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + + thread.start(); + } + //Sensor 3 + public void connectDevice3(View v) { + + Thread thread = new Thread(){ + public void run(){ + + device3.setProtocol(Configuration.COMMUNICATION_TYPE.BLUETOOTH, protocol3); + try { + device3.connect(); + } catch (ShimmerException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + } + }; + + thread.start(); + } + + public void disconnectDevice3(View v) { + Thread thread = new Thread(){ + public void run(){ + try { + isSpeedTestSensor3 = false; + device3.disconnect(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void readOpConfig3(View v) { + Thread thread = new Thread(){ + public void run(){ + try { + protocol3.readOperationalConfig(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void readProdConfig3(View v) { + Thread thread = new Thread(){ + public void run(){ + try { + protocol3.readProductionConfig(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void startStreaming3(View v) throws InterruptedException, IOException, ShimmerException { + Thread thread = new Thread(){ + public void run(){ + try { + protocol3.startStreaming(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void stopStreaming3(View v) throws IOException, ShimmerException { + Thread thread = new Thread(){ + public void run(){ + try { + protocol3.stopStreaming(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + thread.start(); + } + + public void startAllSpeedTest(View v) throws IOException, ShimmerException { + + t1 = new Thread(new Runnable() { + + @Override + public void run() { + try { + protocol1.startSpeedTest(); + protocol2.startSpeedTest(); + protocol3.startSpeedTest(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }); + t1.start(); + } + public void stopAllSpeedTest(View v) throws IOException, ShimmerException { + Thread thread = new Thread(){ + public void run(){ + try { + protocol1.stopSpeedTest(); + protocol2.stopSpeedTest(); + protocol3.stopSpeedTest(); + } catch (ShimmerException e) { + e.printStackTrace(); + } + } + }; + + thread.start(); + } + /** + * Sensor 1 + * Messages from the Shimmer device including sensor data are received here + */ + Handler mHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + + switch (msg.what) { + case ShimmerBluetooth.MSG_IDENTIFIER_DATA_PACKET: + if ((msg.obj instanceof ObjectCluster)) { + + //Print data to Logcat + ObjectCluster objectCluster = (ObjectCluster) msg.obj; + + //Retrieve all possible formats for the current sensor device: + Collection allFormats = objectCluster.getCollectionOfFormatClusters(Configuration.Shimmer3.ObjectClusterSensorName.TIMESTAMP); + FormatCluster timeStampCluster = ((FormatCluster)ObjectCluster.returnFormatCluster(allFormats,"CAL")); + double timeStampData = timeStampCluster.mData; + Log.i(LOG_TAG, "Time Stamp: " + timeStampData); + allFormats = objectCluster.getCollectionOfFormatClusters(SensorLIS2DW12.ObjectClusterSensorName.LIS2DW12_ACC_X); + FormatCluster accelXCluster = ((FormatCluster)ObjectCluster.returnFormatCluster(allFormats,"CAL")); + if (accelXCluster!=null) { + double accelXData = accelXCluster.mData; + Log.i(LOG_TAG, "Accel X: " + accelXData); + } + allFormats = objectCluster.getCollectionOfFormatClusters(SensorLIS2DW12.ObjectClusterSensorName.LIS2DW12_ACC_Y); + FormatCluster accelYCluster = ((FormatCluster)ObjectCluster.returnFormatCluster(allFormats,"CAL")); + if (accelXCluster!=null) { + double accelYData = accelYCluster.mData; + Log.i(LOG_TAG, "Accel Y: " + accelYData); + } + allFormats = objectCluster.getCollectionOfFormatClusters(SensorLIS2DW12.ObjectClusterSensorName.LIS2DW12_ACC_Z); + FormatCluster accelZCluster = ((FormatCluster)ObjectCluster.returnFormatCluster(allFormats,"CAL")); + if (accelZCluster!=null) { + double accelZData = accelZCluster.mData; + Log.i(LOG_TAG, "Accel Z: " + accelZData); + } + + } + break; + case Shimmer.MESSAGE_TOAST: + /** Toast messages sent from {@link Shimmer} are received here. E.g. device xxxx now streaming. + * Note that display of these Toast messages is done automatically in the Handler in {@link com.shimmerresearch.android.shimmerService.ShimmerService} */ + Toast.makeText(getApplicationContext(), msg.getData().getString(Shimmer.TOAST), Toast.LENGTH_SHORT).show(); + break; + case ShimmerBluetooth.MSG_IDENTIFIER_STATE_CHANGE: + ShimmerBluetooth.BT_STATE state = null; + String macAddress = ""; + + if (msg.obj instanceof ObjectCluster) { + state = ((ObjectCluster) msg.obj).mState; + macAddress = ((ObjectCluster) msg.obj).getMacAddress(); + } else if (msg.obj instanceof CallbackObject) { + state = ((CallbackObject) msg.obj).mState; + macAddress = ((CallbackObject) msg.obj).mBluetoothAddress; + } + + switch (state) { + case CONNECTED: + break; + case CONNECTING: + break; + case STREAMING: + break; + case STREAMING_AND_SDLOGGING: + break; + case SDLOGGING: + break; + case DISCONNECTED: + isSpeedTestSensor1 = false; + isSpeedTestSensor2 = false; + isSpeedTestSensor3 = false; + break; + } + break; + } + super.handleMessage(msg); + } + }; + /** + * Get the result from the paired devices dialog + * @param requestCode + * @param resultCode + * @param data + */ + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if(requestCode == 2) { + if (resultCode == Activity.RESULT_OK) { + //Get the Bluetooth mac address of the selected device: + String macAdd = data.getStringExtra(EXTRA_DEVICE_ADDRESS); + + } + + } + super.onActivityResult(requestCode, resultCode, data); + } + + +} \ No newline at end of file diff --git a/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/res/drawable-v24/ic_launcher_foreground.xml b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..2b068d11 --- /dev/null +++ b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/res/drawable/ic_launcher_background.xml b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..07d5da9c --- /dev/null +++ b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/res/layout/activity_main.xml b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..b07aabae --- /dev/null +++ b/ShimmerAndroidInstrumentDriver/multiverisenseblebasicexample/src/main/res/layout/activity_main.xml @@ -0,0 +1,253 @@ + + + + + + + + + +