Android Open Source - MovisensGattSensorExample Movisens Sensor






From Project

Back to project page MovisensGattSensorExample.

License

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.

Java Source Code

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));
          }
        }
      }
    }
  }
}




Java Source Code List

com.movisens.gattsensorexample.activities.DeviceScanActivity.java
com.movisens.gattsensorexample.activities.Preferences.java
com.movisens.gattsensorexample.activities.SensorConnected.java
com.movisens.gattsensorexample.activities.SensorDisconnected.java
com.movisens.gattsensorexample.activities.StartActivity.java
com.movisens.gattsensorexample.activities.TimePreference.java
com.movisens.gattsensorexample.application.App.java
com.movisens.gattsensorexample.events.BLEEvent.java
com.movisens.gattsensorexample.events.MeasurementStatus.java
com.movisens.gattsensorexample.events.SensorStatusEvent.java
com.movisens.gattsensorexample.model.CurrentSensorData.java
com.movisens.gattsensorexample.receivers.SystemStateReceiver.java
com.movisens.gattsensorexample.receivers.UpdateAppReceiver.java
com.movisens.gattsensorexample.sensors.MovisensSensor.java
com.movisens.gattsensorexample.services.BluetoothLeService.java
com.movisens.gattsensorexample.services.SamplingService.java
com.movisens.gattsensorexample.utils.BleQueue.java
com.movisens.gattsensorexample.utils.BleUtils.java