Back to project page MovisensGattSensorExample.
The source code is released under:
GNU General Public License
If you think the Android project MovisensGattSensorExample listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.movisens.gattsensorexample.sensors; //from w w w.j a v a2 s .c om import java.util.Date; import java.util.List; import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.Handler; import android.os.IBinder; import android.os.ParcelUuid; import android.util.Log; import android.widget.Toast; import com.movisens.gattsensorexample.activities.Preferences; import com.movisens.gattsensorexample.application.App; import com.movisens.gattsensorexample.events.BLEEvent; import com.movisens.gattsensorexample.events.MeasurementStatus; import com.movisens.gattsensorexample.events.SensorStatusEvent; import com.movisens.gattsensorexample.events.MeasurementStatus.SensorState; import com.movisens.gattsensorexample.events.SensorStatusEvent.SensorStatus; import com.movisens.gattsensorexample.services.BluetoothLeService; import com.movisens.gattsensorexample.utils.BleUtils; import com.movisens.movisensgattlib.MovisensCharacteristic; import com.movisens.movisensgattlib.MovisensService; import com.movisens.movisensgattlib.characteristics.DataAvailable; import com.movisens.movisensgattlib.characteristics.HrvIsValid; import com.movisens.movisensgattlib.characteristics.MeasurementEnabled; import com.movisens.movisensgattlib.characteristics.MovementAcceleration; import com.movisens.movisensgattlib.characteristics.Rmssd; import com.movisens.smartgattlib.Characteristic; import com.movisens.smartgattlib.GattByteBuffer; import com.movisens.smartgattlib.Service; import com.movisens.smartgattlib.characteristics.BatteryLevel; import com.movisens.smartgattlib.characteristics.HeartRateMeasurement; import de.greenrobot.event.EventBus; public class MovisensSensor { private final static String TAG = MovisensSensor.class.getSimpleName(); private BluetoothLeService mBluetoothLeService; private BluetoothAdapter mBluetoothAdapter; private Handler mHandler; private static final int METHOD_SCAN = 1; private static final int METHOD_PAIRED = 2; private static final int METHOD_ADDRESS = 3; private static int connection_method = METHOD_ADDRESS; private boolean mConnected = false; private BluetoothDevice mDevice; private Context mContext; private Timer mTimer; private final Object timerLock = new Object(); private Timer mDeviceTimer; private MeasurementStatus measurementStatus = new MeasurementStatus(); private StateMachine dataReceiverSM; // Retry to establish connection after 10 seconds. private static final long RECONNECT_DELAY = 10000; // Stops scanning after 10 seconds. private static final long SCAN_PERIOD = 10000; public boolean isConnected() { return mConnected; } public void start(Context context) { mContext = context; mHandler = new Handler(); final BluetoothManager bluetoothManager = (BluetoothManager) context .getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); mBluetoothAdapter.cancelDiscovery(); mBluetoothAdapter.enable(); dataReceiverSM = new StateMachine(this); final Intent gattServiceIntent = new Intent(context, BluetoothLeService.class); context.bindService(gattServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); if (BleUtils.hasBluetoothLE(context)) { registerReceivers(); } } public void stop() { searchDevice(false); mConnected = false; mDevice = null; Log.d(TAG, "Stopping service"); if (mContext != null) { unRegisterReceivers(); } else { Log.d(TAG, "No Context"); } synchronized (timerLock) { if (mTimer != null) { mTimer.cancel(); mTimer.purge(); } else { Log.d(TAG, "No Timer"); } } if (mBluetoothLeService != null) { if (mContext != null) { mContext.unbindService(mServiceConnection); } else { Log.d(TAG, "No Context"); } mBluetoothLeService.disconnect(); mBluetoothLeService.close(); } else { Log.d(TAG, "No Bluetooth Service"); } mBluetoothLeService = null; Log.d(TAG, "Finished ending service"); } private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder service) { mBluetoothLeService = ((BluetoothLeService.LocalBinder) service) .getService(); if (!mBluetoothLeService.initialize()) { Log.e(TAG, "Unable to initialize Bluetooth"); } // Connect without delay searchDevice(true); } @Override public void onServiceDisconnected(ComponentName componentName) { if (mBluetoothLeService != null) { mBluetoothLeService.disconnect(); mBluetoothLeService.close(); } mBluetoothLeService = null; } }; private void searchDevice(final boolean enable) { if (connection_method == METHOD_ADDRESS) { if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) { String address = App.app().getPrefs() .getString(Preferences.SENSOR_ADDRESS, ""); BluetoothDevice remoteDevice = mBluetoothAdapter .getRemoteDevice(address); setDevice(remoteDevice); } } else if (connection_method == METHOD_SCAN) { scanLeDevice(enable); } else if (connection_method == METHOD_PAIRED) { if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) { Set<BluetoothDevice> pairedDevices = mBluetoothAdapter .getBondedDevices(); boolean found = false; // If there are paired devices if (pairedDevices.size() > 0) { // Loop through paired devices for (BluetoothDevice device : pairedDevices) { // if (device.getName().startsWith("MOVISENS")) { setDevice(device); found = true; break; // } } } if (!found) { App.app().showToast("No coupled movisens sensor found", Toast.LENGTH_LONG); } } } } private void scanLeDevice(final boolean enable) { if (enable) { if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) { // Stops scanning after a pre-defined scan period. mHandler.postDelayed(stopScanRunnable, SCAN_PERIOD); EventBus.getDefault() .post(new BLEEvent("Scanning for devices")); mBluetoothAdapter.startLeScan(mLeScanCallback); } } else { removeTimers(); if (mBluetoothAdapter != null) { mBluetoothAdapter.stopLeScan(mLeScanCallback); } } } // Device scan callback. private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { if ((mDevice == null || !mConnected || !device.getAddress().equals( mDevice.getAddress()))) { mDevice = device; if (mDeviceTimer != null) { mDeviceTimer.cancel(); mDeviceTimer.purge(); } mDeviceTimer = new Timer(); mDeviceTimer.schedule(new TimerTask() { @Override public void run() { scanLeDevice(false); setDevice(device); } }, 1000); } } }; private Runnable stopScanRunnable = new Runnable() { @Override public void run() { EventBus.getDefault().post(new BLEEvent("Couldn't find anything")); mBluetoothAdapter.stopLeScan(mLeScanCallback); if (!mConnected) { EventBus.getDefault().post( new BLEEvent("Not connected, trying again...")); removeTimers(); synchronized (timerLock) { mTimer = new Timer(); mTimer.schedule(new TimerTask() { @Override public void run() { scanLeDevice(true); } }, SCAN_PERIOD); } } } }; private void removeTimers() { synchronized (timerLock) { if (mTimer != null) { mTimer.cancel(); mTimer.purge(); } } if (mHandler != null) { mHandler.removeCallbacks(stopScanRunnable); } } private void setDevice(BluetoothDevice device) { if (mBluetoothLeService != null) { mBluetoothLeService.disconnect(); // Sleep to wait for disconnect (maybe fixes Gatt server errors and // reconnection issue) // Gatt server error, status: 133, newState: 2 // Gatt server error, status: 257, newState: 0 try { Thread.sleep(1000); } catch (InterruptedException e) { } if (mBluetoothLeService != null) { mBluetoothLeService.close(); } } mDevice = device; if (mDevice != null && mBluetoothLeService != null) { EventBus.getDefault().post( new BLEEvent("Setting device: " + mDevice.getAddress())); if (device.getBondState() == BluetoothDevice.BOND_BONDED) { Log.d(TAG, "BondState: BOND_BONDED"); } else if (device.getBondState() == BluetoothDevice.BOND_BONDING) { Log.d(TAG, "BondState: BOND_BONDING"); } else if (device.getBondState() == BluetoothDevice.BOND_NONE) { Log.d(TAG, "BondState: BOND_NONE"); // Possibility to recreate bond // mDevice.createBond(); } mBluetoothLeService.connect(mDevice.getAddress()); // reconnectDelayed(); } } private void reconnectDelayed() { removeTimers(); synchronized (timerLock) { mTimer = new Timer(); mTimer.schedule(new TimerTask() { @Override public void run() { if (!mConnected) { searchDevice(true); } } }, RECONNECT_DELAY); } } private static IntentFilter makeGattUpdateIntentFilter() { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED); intentFilter .addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED); intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE); intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_ERROR); intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); return intentFilter; } // Handles various events fired by the Service. // ACTION_GATT_CONNECTED: connected to a GATT server. // ACTION_GATT_DISCONNECTED: disconnected from a GATT server. // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services. // ACTION_DATA_AVAILABLE: received data from the device. This can be a // result of read // or notification operations. private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { EventBus.getDefault() .post(new BLEEvent("GATT Connected: " + mDevice.getAddress())); removeTimers(); } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED .equals(action)) { mBluetoothLeService.close(); EventBus.getDefault().post( new BLEEvent("GATT Disconnected: " + mDevice.getAddress())); mConnected = false; EventBus.getDefault().post( new SensorStatusEvent(SensorStatus.Disconnected)); reconnectDelayed(); } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED .equals(action)) { mConnected = true; EventBus.getDefault().post( new BLEEvent("Gatt services discovered")); EventBus.getDefault().post( new SensorStatusEvent(SensorStatus.Connected)); checkMeasurementStatus(); } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { final byte[] data = intent .getByteArrayExtra(BluetoothLeService.EXTRA_DATA); ParcelUuid uuidExtra = intent .getParcelableExtra(BluetoothLeService.EXTRA_CHARACTERISTIC); UUID uuid = uuidExtra.getUuid(); dataReceiverSM.state.receiveData(dataReceiverSM, data, uuid); } else if (BluetoothLeService.ACTION_GATT_SERVICES_ERROR .equals(action)) { EventBus.getDefault().post(new BLEEvent("Gatt services error")); reconnectDelayed(); } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) { EventBus.getDefault().post(new BLEEvent("Bond state changed")); } } }; private final BroadcastReceiver mBlueToothReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { final int state = intent.getIntExtra( BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); switch (state) { case BluetoothAdapter.STATE_ON: EventBus.getDefault().post( new BLEEvent("Bluetooth turned on")); EventBus.getDefault().post( new SensorStatusEvent(SensorStatus.Disconnected)); if (mContext != null) { mContext.registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter()); } reconnectDelayed(); break; case BluetoothAdapter.STATE_OFF: EventBus.getDefault().post( new BLEEvent("Bluetooth turned off")); stopListening(); if (mContext != null) { try { mContext.unregisterReceiver(mGattUpdateReceiver); } catch (Exception exp) { exp.printStackTrace(); } } BluetoothLeService.setBluetooth(true); break; } } } }; private void unRegisterReceivers() { EventBus.getDefault().post(new BLEEvent("Unregistering receivers")); try { mContext.unregisterReceiver(mGattUpdateReceiver); } catch (Exception exp) { exp.printStackTrace(); } try { mContext.unregisterReceiver(mBlueToothReceiver); } catch (Exception exp) { exp.printStackTrace(); } } private void registerReceivers() { EventBus.getDefault().post(new BLEEvent("Registering receivers")); if (mContext != null) { mContext.registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter()); final IntentFilter filter = new IntentFilter( BluetoothAdapter.ACTION_STATE_CHANGED); mContext.registerReceiver(mBlueToothReceiver, filter); } } private void stopListening() { EventBus.getDefault().post(new BLEEvent("Turning off MovisensSensor")); mConnected = false; mDevice = null; EventBus.getDefault().post( new SensorStatusEvent(SensorStatus.Disconnected)); searchDevice(false); if (mBluetoothLeService != null) { mBluetoothLeService.disconnect(); mBluetoothLeService.close(); } } private void checkMeasurementStatus() { dataReceiverSM.reset(); final List<BluetoothGattService> gattServices = mBluetoothLeService .getSupportedGattServices(); BluetoothGattService movisensService = BleUtils.findService( MovisensService.MOVISENS_SERVICE, gattServices); if (movisensService != null) { BleUtils.readCharacteristic( MovisensCharacteristic.MEASUREMENT_ENABLED, "MEASUREMENT_ENABLED", movisensService.getCharacteristics(), mBluetoothLeService); BleUtils.readCharacteristic(MovisensCharacteristic.DATA_AVAILABLE, "DATA_AVAILABLE", movisensService.getCharacteristics(), mBluetoothLeService); } } private void startMeasurement() { final List<BluetoothGattService> gattServices = mBluetoothLeService .getSupportedGattServices(); // BATTERY_SERVICE BluetoothGattService batteryService = BleUtils.findService( Service.BATTERY_SERVICE, gattServices); if (batteryService != null) { BleUtils.readCharacteristic(Characteristic.BATTERY_LEVEL, "BATTERY_LEVEL", batteryService.getCharacteristics(), mBluetoothLeService); BleUtils.enableCharacteristicNotification( Characteristic.BATTERY_LEVEL, "BATTERY_LEVEL", batteryService.getCharacteristics(), mBluetoothLeService); } // ACC_SERVICE BluetoothGattService accService = BleUtils.findService( MovisensService.ACC_SERVICE, gattServices); if (accService != null) { BleUtils.enableCharacteristicNotification( MovisensCharacteristic.MOVEMENTACCELERATION, "MOVEMENTACCELERATION", accService.getCharacteristics(), mBluetoothLeService); } // MOVISENS_SERVICE BluetoothGattService movisensService = BleUtils.findService( MovisensService.MOVISENS_SERVICE, gattServices); if (movisensService != null) { BleUtils.writeCharacteristic(MovisensCharacteristic.CURRENT_TIME, "CURRENT_TIME", movisensService.getCharacteristics(), mBluetoothLeService, getLocalTime()); byte[] enable = GattByteBuffer.allocate(1).putBoolean(true).array(); BleUtils.writeCharacteristic( MovisensCharacteristic.MEASUREMENT_ENABLED, "MEASUREMENT_ENABLED", movisensService.getCharacteristics(), mBluetoothLeService, enable); BleUtils.enableCharacteristicNotification( MovisensCharacteristic.MEASUREMENT_ENABLED, "MEASUREMENT_ENABLED", movisensService.getCharacteristics(), mBluetoothLeService); BleUtils.writeCharacteristic(MovisensCharacteristic.AUTHORIZE, "AUTHORIZE", movisensService.getCharacteristics(), mBluetoothLeService, enable); } } private byte[] getLocalTime() { long time = new Date().getTime(); while ((time % 1000) > 5) { time = new Date().getTime(); } GattByteBuffer timeBB = GattByteBuffer.allocate(4); return timeBB.putUint32(time / 1000).array(); } public void finishMeasurement() { final List<BluetoothGattService> gattServices = mBluetoothLeService .getSupportedGattServices(); // MOVISENS_SERVICE BluetoothGattService movisensService = BleUtils.findService( MovisensService.MOVISENS_SERVICE, gattServices); if (movisensService != null) { byte[] by = new byte[1]; by[0] = 0; BleUtils.writeCharacteristic( MovisensCharacteristic.MEASUREMENT_ENABLED, "MEASUREMENT_ENABLED", movisensService.getCharacteristics(), mBluetoothLeService, by); } } // The StateMachine class public static class StateMachine { MovisensSensor context; State state; StateMachine(MovisensSensor context) { this.context = context; reset(); } interface State { void receiveData(StateMachine sm, final byte[] data, UUID uuid); } public void reset() { state = States.WAIT_FOR_MEASUREMENT_ENABLED; // default } enum States implements State { WAIT_FOR_MEASUREMENT_ENABLED { public void receiveData(StateMachine sm, final byte[] data, UUID uuid) { if (Characteristic.HEART_RATE_MEASUREMENT.equals(uuid)) { HeartRateMeasurement hrm = new HeartRateMeasurement( data); hrm.getHr(); } if (MovisensCharacteristic.MEASUREMENT_ENABLED.equals(uuid)) { MeasurementEnabled measurementEnabled = new MeasurementEnabled( data); sm.context.measurementStatus.measurementEnabled = measurementEnabled .getValue() ? SensorState.True : SensorState.False; sm.state = WAIT_FOR_DATA_AVAILABLE; } } }, WAIT_FOR_DATA_AVAILABLE { public void receiveData(StateMachine sm, final byte[] data, UUID uuid) { DataAvailable dataAvailable = new DataAvailable(data); EventBus.getDefault().post(dataAvailable); MeasurementStatus measurementStatus = sm.context.measurementStatus; measurementStatus.dataAvailable = dataAvailable.getValue() ? SensorState.True : SensorState.False; if (measurementStatus.measurementEnabled == SensorState.False && measurementStatus.dataAvailable == SensorState.True) { EventBus.getDefault().post(measurementStatus); } else { sm.state = RUNNING; sm.context.startMeasurement(); } } }, RUNNING { public void receiveData(StateMachine sm, final byte[] data, UUID uuid) { Log.d(TAG, "Received data from characteristic: " + uuid.toString() + ", data: " + BleUtils.bytesToHex(data)); if (MovisensCharacteristic.RMSSD.equals(uuid)) { EventBus.getDefault().post(new Rmssd(data)); } if (MovisensCharacteristic.HRVISVALID.equals(uuid)) { EventBus.getDefault().post(new HrvIsValid(data)); } if (MovisensCharacteristic.MOVEMENTACCELERATION .equals(uuid)) { EventBus.getDefault().post( new MovementAcceleration(data)); } if (Characteristic.BATTERY_LEVEL.equals(uuid)) { EventBus.getDefault().post(new BatteryLevel(data)); } if (MovisensCharacteristic.MEASUREMENT_ENABLED.equals(uuid)) { MeasurementEnabled measurementEnabled = new MeasurementEnabled( data); EventBus.getDefault().post(measurementEnabled); } if (Characteristic.HEART_RATE_MEASUREMENT.equals(uuid)) { EventBus.getDefault().post( new HeartRateMeasurement(data)); } } } } } }