CGMS profile fixed, BleManager callback report BluetootDevice

This commit fixes some issues in CGMS profile. It also modiefied the
BleManager and BleManagerCallback to report the related BluetoothDevice
object. This is a preparation for adding multiconnect support.
This commit is contained in:
Aleksander Nowakowski
2016-10-05 12:42:40 +02:00
parent de66db95be
commit f7b7d70954
54 changed files with 1649 additions and 1076 deletions

View File

@@ -21,6 +21,7 @@
*/
package no.nordicsemi.android.nrftoolbox.bpm;
import android.bluetooth.BluetoothDevice;
import android.os.Bundle;
import android.widget.TextView;
@@ -102,23 +103,23 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
}
@Override
public void onServicesDiscovered(final boolean optionalServicesFound) {
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
// this may notify user or show some views
}
@Override
public void onDeviceReady() {
public void onDeviceReady(final BluetoothDevice device) {
// this may notify user
}
@Override
public void onBloodPressureMeasurementRead(final float systolic, final float diastolic, final float meanArterialPressure, final int unit) {
public void onBloodPressureMeasurementRead(final BluetoothDevice device, final float systolic, final float diastolic, final float meanArterialPressure, final int unit) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mSystolicView.setText(Float.toString(systolic));
mDiastolicView.setText(Float.toString(diastolic));
mMeanAPView.setText(Float.toString(meanArterialPressure));
mSystolicView.setText(String.valueOf(systolic));
mDiastolicView.setText(String.valueOf(diastolic));
mMeanAPView.setText(String.valueOf(meanArterialPressure));
mSystolicUnitView.setText(unit == UNIT_mmHG ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa);
mDiastolicUnitView.setText(unit == UNIT_mmHG ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa);
@@ -128,11 +129,11 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
}
@Override
public void onIntermediateCuffPressureRead(final float cuffPressure, final int unit) {
public void onIntermediateCuffPressureRead(final BluetoothDevice device, final float cuffPressure, final int unit) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mSystolicView.setText(Float.toString(cuffPressure));
mSystolicView.setText(String.valueOf(cuffPressure));
mDiastolicView.setText(R.string.not_available_value);
mMeanAPView.setText(R.string.not_available_value);
@@ -144,12 +145,12 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
}
@Override
public void onPulseRateRead(final float pulseRate) {
public void onPulseRateRead(final BluetoothDevice device, final float pulseRate) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (pulseRate >= 0)
mPulseView.setText(Float.toString(pulseRate));
mPulseView.setText(String.valueOf(pulseRate));
else
mPulseView.setText(R.string.not_available_value);
}
@@ -157,7 +158,7 @@ public class BPMActivity extends BleProfileActivity implements BPMManagerCallbac
}
@Override
public void onTimestampRead(final Calendar calendar) {
public void onTimestampRead(final BluetoothDevice device, final Calendar calendar) {
runOnUiThread(new Runnable() {
@Override
public void run() {

View File

@@ -76,8 +76,8 @@ public class BPMManager extends BleManager<BPMManagerCallbacks> {
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
if (mICPCharacteristic != null)
requests.push(Request.newEnableNotificationsRequest(mICPCharacteristic));
requests.push(Request.newEnableIndicationsRequest(mBPMCharacteristic));
requests.add(Request.newEnableNotificationsRequest(mICPCharacteristic));
requests.add(Request.newEnableIndicationsRequest(mBPMCharacteristic));
return requests;
}
@@ -105,22 +105,20 @@ public class BPMManager extends BleManager<BPMManagerCallbacks> {
@Override
protected void onCharacteristicNotified(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
// Intermediate Cuff Pressure characteristic read
if (mLogSession != null)
Logger.a(mLogSession, IntermediateCuffPressureParser.parse(characteristic));
Logger.a(mLogSession, "\"" + IntermediateCuffPressureParser.parse(characteristic) + "\" received");
parseBPMValue(characteristic);
parseBPMValue(gatt, characteristic);
}
@Override
protected void onCharacteristicIndicated(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
// Blood Pressure Measurement characteristic read
if (mLogSession != null)
Logger.a(mLogSession, BloodPressureMeasurementParser.parse(characteristic));
Logger.a(mLogSession, "\"" + BloodPressureMeasurementParser.parse(characteristic) + "\" received");
parseBPMValue(characteristic);
parseBPMValue(gatt, characteristic);
}
private void parseBPMValue(final BluetoothGattCharacteristic characteristic) {
private void parseBPMValue(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
// Both BPM and ICP have the same structure.
// first byte - flags
@@ -137,12 +135,12 @@ public class BPMManager extends BleManager<BPMManagerCallbacks> {
final float diastolic = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset + 2);
final float meanArterialPressure = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset + 4);
offset += 6;
mCallbacks.onBloodPressureMeasurementRead(systolic, diastolic, meanArterialPressure, unit);
mCallbacks.onBloodPressureMeasurementRead(gatt.getDevice(), systolic, diastolic, meanArterialPressure, unit);
} else if (ICP_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {
// following bytes - cuff pressure. Diastolic and MAP are unused
final float cuffPressure = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset);
offset += 6;
mCallbacks.onIntermediateCuffPressureRead(cuffPressure, unit);
mCallbacks.onIntermediateCuffPressureRead(gatt.getDevice(), cuffPressure, unit);
}
// parse timestamp if present
@@ -155,17 +153,17 @@ public class BPMManager extends BleManager<BPMManagerCallbacks> {
calendar.set(Calendar.MINUTE, characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 5));
calendar.set(Calendar.SECOND, characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 6));
offset += 7;
mCallbacks.onTimestampRead(calendar);
mCallbacks.onTimestampRead(gatt.getDevice(), calendar);
} else
mCallbacks.onTimestampRead(null);
mCallbacks.onTimestampRead(gatt.getDevice(), null);
// parse pulse rate if present
if (pulseRatePresent) {
final float pulseRate = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset);
// offset += 2;
mCallbacks.onPulseRateRead(pulseRate);
mCallbacks.onPulseRateRead(gatt.getDevice(), pulseRate);
} else
mCallbacks.onPulseRateRead(-1.0f);
mCallbacks.onPulseRateRead(gatt.getDevice(), -1.0f);
}
};
}

View File

@@ -21,47 +21,53 @@
*/
package no.nordicsemi.android.nrftoolbox.bpm;
import android.bluetooth.BluetoothDevice;
import java.util.Calendar;
import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
public interface BPMManagerCallbacks extends BleManagerCallbacks {
public static final int UNIT_mmHG = 0;
public static final int UNIT_kPa = 1;
int UNIT_mmHG = 0;
int UNIT_kPa = 1;
/**
* Called when new BPM value has been obtained from the sensor
*
*
* @param device the target device
* @param systolic
* @param diastolic
* @param meanArterialPressure
* @param unit
* one of the following {@link #UNIT_kPa} or {@link #UNIT_mmHG}
*/
public void onBloodPressureMeasurementRead(final float systolic, final float diastolic, final float meanArterialPressure, final int unit);
void onBloodPressureMeasurementRead(final BluetoothDevice device, final float systolic, final float diastolic, final float meanArterialPressure, final int unit);
/**
* Called when new ICP value has been obtained from the device
*
*
* @param device the target device
* @param cuffPressure
* @param unit
* one of the following {@link #UNIT_kPa} or {@link #UNIT_mmHG}
*/
public void onIntermediateCuffPressureRead(final float cuffPressure, final int unit);
void onIntermediateCuffPressureRead(final BluetoothDevice device, final float cuffPressure, final int unit);
/**
* Called when new pulse rate value has been obtained from the device. If there was no pulse rate in the packet the parameter will be equal -1.0f
*
*
* @param device the target device
* @param pulseRate
* pulse rate or -1.0f
*/
public void onPulseRateRead(final float pulseRate);
void onPulseRateRead(final BluetoothDevice device, final float pulseRate);
/**
* Called when the timestamp value has been read from the device. If there was no timestamp information the parameter will be <code>null</code>
*
*
* @param device the target device
* @param calendar
* the timestamp or <code>null</code>
*/
public void onTimestampRead(final Calendar calendar);
void onTimestampRead(final BluetoothDevice device, final Calendar calendar);
}

View File

@@ -22,6 +22,7 @@
package no.nordicsemi.android.nrftoolbox.cgms;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -34,7 +35,6 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.TextView;
import java.util.UUID;
@@ -42,251 +42,232 @@ import no.nordicsemi.android.nrftoolbox.R;
import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity;
public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMSBinder> implements PopupMenu.OnMenuItemClickListener {
public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMSBinder> implements PopupMenu.OnMenuItemClickListener {
private View mControlPanelStd;
private View mControlPanelAbort;
private ListView mRecordsListView;
private CGMSRecordsAdapter mCgmsRecordsAdapter;
private View mControlPanelStd;
private View mControlPanelAbort;
private TextView mUnitView;
private ListView mRecordsListView;
private CGMSRecordsAdapter mCgmsRecordsAdapter;
private CGMService.CGMSBinder mBinder;
private CGMService.CGMSBinder mBinder;
@Override
protected void onCreateView(Bundle savedInstanceState) {
setContentView(R.layout.activity_feature_cgms);
setGUI();
}
@Override
protected void onCreateView(Bundle savedInstanceState) {
setContentView(R.layout.activity_feature_cgms);
setGUI();
}
@Override
protected void onInitialize(Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
}
@Override
protected void onInitialize(Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
}
private void setGUI() {
mRecordsListView = (ListView) findViewById(R.id.list);
mControlPanelStd = findViewById(R.id.cgms_control_std);
mControlPanelAbort = findViewById(R.id.cgms_control_abort);
private void setGUI() {
mRecordsListView = (ListView) findViewById(R.id.list);
mUnitView = (TextView) findViewById(R.id.unit);
mControlPanelStd = findViewById(R.id.cgms_control_std);
mControlPanelAbort = findViewById(R.id.cgms_control_abort);
findViewById(R.id.action_last).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clearRecords();
if (mBinder != null) {
mBinder.clear();
mBinder.getLastRecord();
}
}
});
findViewById(R.id.action_all).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clearRecords();
if (mBinder != null) {
clearRecords();
mBinder.getAllRecords();
}
}
});
findViewById(R.id.action_abort).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mBinder != null) {
mBinder.abort();
}
}
});
findViewById(R.id.action_last).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clearRecords();
if(mBinder != null) {
mBinder.clear();
mBinder.getLastRecord();
}
}
});
findViewById(R.id.action_all).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clearRecords();
if(mBinder != null){
clearRecords();
mBinder.getAllRecords();
}
}
});
findViewById(R.id.action_abort).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mBinder != null){
mBinder.abort();
}
}
});
// create popup menu attached to the button More
findViewById(R.id.action_more).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PopupMenu menu = new PopupMenu(CGMSActivity.this, v);
menu.setOnMenuItemClickListener(CGMSActivity.this);
MenuInflater inflater = menu.getMenuInflater();
inflater.inflate(R.menu.gls_more, menu.getMenu());
menu.show();
}
});
}
// create popup menu attached to the button More
findViewById(R.id.action_more).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PopupMenu menu = new PopupMenu(CGMSActivity.this, v);
menu.setOnMenuItemClickListener(CGMSActivity.this);
MenuInflater inflater = menu.getMenuInflater();
inflater.inflate(R.menu.gls_more, menu.getMenu());
menu.show();
}
});
}
private void loadAdapter(SparseArray<CGMSRecord> records) {
mCgmsRecordsAdapter.clear();
for (int i = 0; i < records.size(); i++) {
mCgmsRecordsAdapter.addItem(records.valueAt(i));
}
mCgmsRecordsAdapter.notifyDataSetChanged();
}
private void loadAdapter(SparseArray<CGMSRecord> records){
for(int i = 0; i < records.size(); i++){
mCgmsRecordsAdapter.addItem(records.get(i));
}
mCgmsRecordsAdapter.notifyDataSetChanged();
}
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
}
@Override
protected void onServiceBinded(final CGMService.CGMSBinder binder) {
mBinder = binder;
final SparseArray<CGMSRecord> cgmsRecords = binder.getRecords();
if (cgmsRecords != null && cgmsRecords.size() > 0) {
if (mCgmsRecordsAdapter == null) {
mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
mRecordsListView.setAdapter(mCgmsRecordsAdapter);
}
loadAdapter(cgmsRecords);
}
}
@Override
protected void onServiceBinded(CGMService.CGMSBinder binder) {
mBinder = binder;
SparseArray<CGMSRecord> cgmsRecords = binder.getCgmsRecords();
if(cgmsRecords != null && cgmsRecords.size() > 0){
if(mCgmsRecordsAdapter == null) {
mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
mRecordsListView.setAdapter(mCgmsRecordsAdapter);
}
loadAdapter(cgmsRecords);
}
}
@Override
protected void onServiceUnbinded() {
mBinder = null;
}
@Override
protected void onServiceUnbinded() {
mBinder = null;
}
@Override
protected Class<? extends BleProfileService> getServiceClass() {
return CGMService.class;
}
@Override
protected Class<? extends BleProfileService> getServiceClass() {
return CGMService.class;
}
@Override
protected int getLoggerProfileTitle() {
return R.string.cgms_feature_title;
}
@Override
protected int getLoggerProfileTitle() {
return R.string.cgms_feature_title;
}
@Override
protected int getAboutTextId() {
return R.string.cgms_about_text;
}
@Override
protected int getAboutTextId() {
return R.string.cgms_about_text;
}
@Override
protected int getDefaultDeviceName() {
return R.string.cgms_default_name;
}
@Override
protected int getDefaultDeviceName() {
return R.string.cgms_default_name;
}
@Override
protected UUID getFilterUUID() {
return CGMSManager.CGMS_UUID;
}
@Override
protected UUID getFilterUUID() {
return CGMSManager.CGMS_UUID;
}
@Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
// this may notify user or show some views
}
@Override
public void onServicesDiscovered(final boolean optionalServicesFound) {
// this may notify user or show some views
}
private void setOperationInProgress(final boolean progress) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// setSupportProgressBarIndeterminateVisibility(progress);
mControlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE);
mControlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE);
}
});
}
@Override
public void onDeviceReady() {
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
super.onDeviceDisconnected(device);
setOperationInProgress(false);
clearRecords();
}
}
@Override
protected void setDefaultUI() {
// do nothing
}
private void setOperationInProgress(final boolean progress) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// setSupportProgressBarIndeterminateVisibility(progress);
mControlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE);
mControlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE);
}
});
}
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.action_refresh:
if(mBinder != null)
mBinder.refreshRecords();
break;
case R.id.action_first:
if (mBinder != null)
mBinder.getFirstRecord();
break;
case R.id.action_clear:
if (mBinder != null)
mBinder.clear();
break;
case R.id.action_delete_all:
if (mBinder != null)
mBinder.deleteAllRecords();
break;
}
return true;
}
@Override
public void onDeviceDisconnected() {
super.onDeviceDisconnected();
setOperationInProgress(false);
clearRecords();
}
private void clearRecords() {
if (mCgmsRecordsAdapter != null) {
mCgmsRecordsAdapter.clear();
mCgmsRecordsAdapter.notifyDataSetChanged();
}
}
@Override
protected void setDefaultUI() {
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
}
switch (action) {
case CGMService.BROADCAST_NEW_CGMS_VALUE: {
CGMSRecord cgmsRecord = intent.getExtras().getParcelable(CGMService.EXTRA_CGMS_RECORD);
if (mCgmsRecordsAdapter == null) {
mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
mRecordsListView.setAdapter(mCgmsRecordsAdapter);
}
mCgmsRecordsAdapter.addItem(cgmsRecord);
mCgmsRecordsAdapter.notifyDataSetChanged();
break;
}
case CGMService.BROADCAST_DATA_SET_CLEAR:
// Update GUI
clearRecords();
break;
case CGMService.OPERATION_STARTED:
// Update GUI
setOperationInProgress(true);
break;
case CGMService.OPERATION_FAILED:
// Update GUI
showToast(R.string.gls_operation_failed);
// breakthrough intended
default:
// Update GUI
setOperationInProgress(false);
}
}
};
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.action_refresh:
/*if(mBinder != null)
mBinder.refreshRecords();*/
break;
case R.id.action_first:
clearRecords();
if(mBinder != null)
mBinder.getFirstRecord();
break;
case R.id.action_clear:
clearRecords();
if(mBinder != null)
mBinder.clear();
break;
case R.id.action_delete_all:
clearRecords();
if(mBinder != null)
mBinder.deleteAllRecords();
break;
}
return true;
}
private void clearRecords(){
runOnUiThread(new Runnable() {
@Override
public void run() {
if(mCgmsRecordsAdapter != null){
mCgmsRecordsAdapter.clear();
mCgmsRecordsAdapter.notifyDataSetChanged();
}
}
});
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
if (CGMService.BROADCAST_CGMS_VALUES.equals(action)) {
CGMSRecord cgmsRecord = intent.getExtras().getParcelable(CGMService.EXTRA_CGMS_RECORD);
if(mCgmsRecordsAdapter == null){
mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
mRecordsListView.setAdapter(mCgmsRecordsAdapter);
}
mCgmsRecordsAdapter.addItem(cgmsRecord);
mCgmsRecordsAdapter.notifyDataSetChanged();
} else if (CGMService.BROADCAST_DATA_SET_CHANGED.equals(action)) {
// Update GUI
clearRecords();
} else if (CGMService.OPERATION_STARTED.equals(action)) {
// Update GUI
setOperationInProgress(true);
} else if (CGMService.OPERATION_COMPLETED.equals(action)) {
// Update GUI
setOperationInProgress(false);
} else if (CGMService.OPERATION_SUPPORTED.equals(action)) {
// Update GUI
setOperationInProgress(false);
} else if (CGMService.OPERATION_NOT_SUPPORTED.equals(action)) {
// Update GUI
setOperationInProgress(false);
} else if (CGMService.OPERATION_ABORTED.equals(action)) {
// Update GUI
setOperationInProgress(false);
} else if (CGMService.OPERATION_FAILED.equals(action)) {
// Update GUI
setOperationInProgress(false);
showToast(R.string.gls_operation_failed);
}
}
};
private static IntentFilter makeIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(CGMService.BROADCAST_CGMS_VALUES);
intentFilter.addAction(CGMService.BROADCAST_DATA_SET_CHANGED);
intentFilter.addAction(CGMService.OPERATION_STARTED);
intentFilter.addAction(CGMService.OPERATION_COMPLETED);
intentFilter.addAction(CGMService.OPERATION_SUPPORTED);
intentFilter.addAction(CGMService.OPERATION_NOT_SUPPORTED);
intentFilter.addAction(CGMService.OPERATION_ABORTED);
intentFilter.addAction(CGMService.OPERATION_FAILED);
return intentFilter;
}
private static IntentFilter makeIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(CGMService.BROADCAST_NEW_CGMS_VALUE);
intentFilter.addAction(CGMService.BROADCAST_DATA_SET_CLEAR);
intentFilter.addAction(CGMService.OPERATION_STARTED);
intentFilter.addAction(CGMService.OPERATION_COMPLETED);
intentFilter.addAction(CGMService.OPERATION_SUPPORTED);
intentFilter.addAction(CGMService.OPERATION_NOT_SUPPORTED);
intentFilter.addAction(CGMService.OPERATION_ABORTED);
intentFilter.addAction(CGMService.OPERATION_FAILED);
return intentFilter;
}
}

View File

@@ -26,19 +26,15 @@ import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.nfc.Tag;
import android.util.Log;
import android.util.SparseArray;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.Queue;
import java.util.UUID;
import no.nordicsemi.android.log.Logger;
import no.nordicsemi.android.nrftoolbox.parser.HeartRateMeasurementParser;
import no.nordicsemi.android.nrftoolbox.parser.CGMMeasurementParser;
import no.nordicsemi.android.nrftoolbox.parser.CGMSpecificOpsControlPointParser;
import no.nordicsemi.android.nrftoolbox.parser.RecordAccessControlPointParser;
import no.nordicsemi.android.nrftoolbox.profile.BleManager;
import no.nordicsemi.android.nrftoolbox.utility.DebugLogger;
@@ -47,337 +43,363 @@ import no.nordicsemi.android.nrftoolbox.utility.DebugLogger;
* Created by rora on 10.05.2016.
*/
public class CGMSManager extends BleManager<CGMSManagerCallbacks> {
private static final String TAG = "CGMSManager";
private static final String TAG = "CGMSManager";
/** Cycling Speed and Cadence service UUID */
public final static UUID CGMS_UUID = UUID.fromString("0000181F-0000-1000-8000-00805f9b34fb");
private static final UUID CGM_MEASUREMENT_UUID = UUID.fromString("00002AA7-0000-1000-8000-00805f9b34fb");
private static final UUID CGM_OPS_CONTROL_POINT_UUID = UUID.fromString("00002AAC-0000-1000-8000-00805f9b34fb");
/** Record Access Control Point characteristic UUID */
private final static UUID RACP_UUID = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb");
/**
* Cycling Speed and Cadence service UUID
*/
public final static UUID CGMS_UUID = UUID.fromString("0000181F-0000-1000-8000-00805f9b34fb");
private static final UUID CGM_MEASUREMENT_UUID = UUID.fromString("00002AA7-0000-1000-8000-00805f9b34fb");
private static final UUID CGM_OPS_CONTROL_POINT_UUID = UUID.fromString("00002AAC-0000-1000-8000-00805f9b34fb");
private final static int OP_CODE_START_SESSION = 26;
/**
* Record Access Control Point characteristic UUID
*/
private final static UUID RACP_UUID = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb");
private final static int OP_CODE_REPORT_STORED_RECORDS = 1;
private final static int OP_CODE_DELETE_STORED_RECORDS = 2;
private final static int OP_CODE_ABORT_OPERATION = 3;
private final static int OP_CODE_REPORT_NUMBER_OF_RECORDS = 4;
private final static int OP_CODE_NUMBER_OF_STORED_RECORDS_RESPONSE = 5;
private final static int OP_CODE_RESPONSE_CODE = 6;
private final static int OP_CODE_REPORT_STORED_RECORDS = 1;
private final static int OP_CODE_DELETE_STORED_RECORDS = 2;
private final static int OP_CODE_ABORT_OPERATION = 3;
private final static int OP_CODE_REPORT_NUMBER_OF_RECORDS = 4;
private final static int OP_CODE_NUMBER_OF_STORED_RECORDS_RESPONSE = 5;
private final static int OP_CODE_RESPONSE_CODE = 6;
private final static int OPERATOR_NULL = 0;
private final static int OPERATOR_ALL_RECORDS = 1;
private final static int OPERATOR_LESS_THEN_OR_EQUAL = 2;
private final static int OPERATOR_GREATER_THEN_OR_EQUAL = 3;
private final static int OPERATOR_WITHING_RANGE = 4;
private final static int OPERATOR_FIRST_RECORD = 5;
private final static int OPERATOR_LAST_RECORD = 6;
private final static int OPERATOR_NULL = 0;
private final static int OPERATOR_ALL_RECORDS = 1;
private final static int OPERATOR_LESS_THEN_OR_EQUAL = 2;
private final static int OPERATOR_GREATER_THEN_OR_EQUAL = 3;
private final static int OPERATOR_WITHING_RANGE = 4;
private final static int OPERATOR_FIRST_RECORD = 5;
private final static int OPERATOR_LAST_RECORD = 6;
/**
* The filter type is used for range operators ({@link #OPERATOR_LESS_THEN_OR_EQUAL}, {@link #OPERATOR_GREATER_THEN_OR_EQUAL}, {@link #OPERATOR_WITHING_RANGE}.<br/>
* The syntax of the operand is: [Filter Type][Minimum][Maximum].<br/>
* This filter selects the records by the sequence number.
*/
private final static int FILTER_TYPE_SEQUENCE_NUMBER = 1;
/**
* The filter type is used for range operators ({@link #OPERATOR_LESS_THEN_OR_EQUAL}, {@link #OPERATOR_GREATER_THEN_OR_EQUAL}, {@link #OPERATOR_WITHING_RANGE}.<br/>
* The syntax of the operand is: [Filter Type][Minimum][Maximum].<br/>
* This filter selects the records by the user facing time (base time + offset time).
*/
private final static int FILTER_TYPE_USER_FACING_TIME = 2;
private final static int RESPONSE_SUCCESS = 1;
private final static int RESPONSE_OP_CODE_NOT_SUPPORTED = 2;
private final static int RESPONSE_INVALID_OPERATOR = 3;
private final static int RESPONSE_OPERATOR_NOT_SUPPORTED = 4;
private final static int RESPONSE_INVALID_OPERAND = 5;
private final static int RESPONSE_NO_RECORDS_FOUND = 6;
private final static int RESPONSE_ABORT_UNSUCCESSFUL = 7;
private final static int RESPONSE_PROCEDURE_NOT_COMPLETED = 8;
private final static int RESPONSE_OPERAND_NOT_SUPPORTED = 9;
/**
* The filter type is used for range operators ({@link #OPERATOR_LESS_THEN_OR_EQUAL}, {@link #OPERATOR_GREATER_THEN_OR_EQUAL}, {@link #OPERATOR_WITHING_RANGE}.<br/>
* The syntax of the operand is: [Filter Type][Minimum][Maximum].<br/>
* This filter selects the records by the sequence number.
*/
private final static int FILTER_TYPE_SEQUENCE_NUMBER = 1;
/**
* The filter type is used for range operators ({@link #OPERATOR_LESS_THEN_OR_EQUAL}, {@link #OPERATOR_GREATER_THEN_OR_EQUAL}, {@link #OPERATOR_WITHING_RANGE}.<br/>
* The syntax of the operand is: [Filter Type][Minimum][Maximum].<br/>
* This filter selects the records by the user facing time (base time + offset time).
*/
private final static int FILTER_TYPE_USER_FACING_TIME = 2;
private final static int RESPONSE_SUCCESS = 1;
private final static int RESPONSE_OP_CODE_NOT_SUPPORTED = 2;
private final static int RESPONSE_INVALID_OPERATOR = 3;
private final static int RESPONSE_OPERATOR_NOT_SUPPORTED = 4;
private final static int RESPONSE_INVALID_OPERAND = 5;
private final static int RESPONSE_NO_RECORDS_FOUND = 6;
private final static int RESPONSE_ABORT_UNSUCCESSFUL = 7;
private final static int RESPONSE_PROCEDURE_NOT_COMPLETED = 8;
private final static int RESPONSE_OPERAND_NOT_SUPPORTED = 9;
private final static SimpleDateFormat mTimeFormat= new SimpleDateFormat("dd MM YYYY HH:mm:ss");
private BluetoothGattCharacteristic mCGMMeasurementCharacteristic;
private BluetoothGattCharacteristic mCGMOpsControlPointCharacteristic;
private BluetoothGattCharacteristic mRecordAccessControlPointCharacteristic;
private BluetoothGattCharacteristic mCGMMEasurementCharacteristic;
private BluetoothGattCharacteristic mCGMOpsControlPointCharacteristic;
private BluetoothGattCharacteristic mRecordAccessControlPointCharacteristic;
private static CGMSManager managerInstance = null;
private SparseArray<CGMSRecord> mRecords = new SparseArray<>();
private boolean mAbort;
private long mSessionStartTime;
private static CGMSManager managerInstance = null;
private SparseArray<CGMSRecord> mRecords = new SparseArray<>();
private boolean mAbort;
private long mSessionStartTime;
/**
* singleton implementation of HRSManager class
*/
public static synchronized CGMSManager getInstance(final Context context) {
if (managerInstance == null) {
managerInstance = new CGMSManager(context);
}
return managerInstance;
}
/**
* singleton implementation of HRSManager class
*/
public static synchronized CGMSManager getInstance(final Context context) {
if (managerInstance == null) {
managerInstance = new CGMSManager(context);
}
return managerInstance;
}
public CGMSManager(Context context) {
super(context);
}
public CGMSManager(Context context) {
super(context);
}
@Override
protected BleManagerGattCallback getGattCallback() {
return mGattCallback;
}
@Override
protected BleManagerGattCallback getGattCallback() {
return mGattCallback;
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery, receiving notification, etc
*/
private final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() {
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery, receiving notification, etc
*/
private final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() {
@Override
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
requests.push(Request.newEnableNotificationsRequest(mCGMMEasurementCharacteristic));
if (mCGMOpsControlPointCharacteristic != null) {
mSessionStartTime = System.currentTimeMillis();
requests.push(Request.newWriteRequest(mCGMOpsControlPointCharacteristic, new byte[]{26} /*start session value*/));
}
requests.push(Request.newEnableIndicationsRequest(mRecordAccessControlPointCharacteristic));
return requests;
}
@Override
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
requests.add(Request.newEnableNotificationsRequest(mCGMMeasurementCharacteristic));
if (mCGMOpsControlPointCharacteristic != null) {
mSessionStartTime = System.currentTimeMillis();
requests.add(Request.newEnableIndicationsRequest(mCGMOpsControlPointCharacteristic));
requests.add(Request.newWriteRequest(mCGMOpsControlPointCharacteristic, new byte[]{OP_CODE_START_SESSION}));
}
requests.add(Request.newEnableIndicationsRequest(mRecordAccessControlPointCharacteristic));
return requests;
}
@Override
protected boolean isRequiredServiceSupported(final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(CGMS_UUID);
if (service != null) {
mCGMMEasurementCharacteristic = service.getCharacteristic(CGM_MEASUREMENT_UUID);
mCGMOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
mRecordAccessControlPointCharacteristic = service.getCharacteristic(RACP_UUID);
}
return mCGMMEasurementCharacteristic != null && mCGMOpsControlPointCharacteristic != null && mRecordAccessControlPointCharacteristic != null;
}
@Override
protected boolean isRequiredServiceSupported(final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(CGMS_UUID);
if (service != null) {
mCGMMeasurementCharacteristic = service.getCharacteristic(CGM_MEASUREMENT_UUID);
mCGMOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
mRecordAccessControlPointCharacteristic = service.getCharacteristic(RACP_UUID);
}
return mCGMMeasurementCharacteristic != null && mCGMOpsControlPointCharacteristic != null && mRecordAccessControlPointCharacteristic != null;
}
@Override
protected boolean isOptionalServiceSupported(final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(CGMS_UUID);
if (service != null) {
mCGMOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
}
return mCGMOpsControlPointCharacteristic != null;
}
@Override
protected boolean isOptionalServiceSupported(final BluetoothGatt gatt) {
final BluetoothGattService service = gatt.getService(CGMS_UUID);
if (service != null) {
mCGMOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
}
return mCGMOpsControlPointCharacteristic != null;
}
@Override
public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
}
@Override
public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
}
@Override
protected void onDeviceDisconnected() {
mCGMOpsControlPointCharacteristic = null;
mCGMMEasurementCharacteristic = null;
//mRecordAccessControlPointCharacteristic = null;
}
@Override
protected void onDeviceDisconnected() {
mCGMOpsControlPointCharacteristic = null;
mCGMMeasurementCharacteristic = null;
mRecordAccessControlPointCharacteristic = null;
}
@Override
public void onCharacteristicNotified(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
final UUID uuid = characteristic.getUuid();
if(CGM_MEASUREMENT_UUID.equals(uuid)) {
if (mLogSession != null)
Logger.a(mLogSession, HeartRateMeasurementParser.parse(characteristic));
byte [] data = characteristic.getValue();
int cgmSize = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
float cgmValue;
int timeOffset;
if (cgmSize > 0) {
cgmValue = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, 2);
timeOffset = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 4);
Date date = new Date(mSessionStartTime + (timeOffset * 3600));
final String timeStamp = mTimeFormat.format(date);
//This will send callback to CGMSActivity when new concentration value is received from CGMS device
mCallbacks.onCGMValueReceived(cgmValue, timeStamp);
}
} else if (CGM_OPS_CONTROL_POINT_UUID.equals(uuid)){
Log.v(TAG, "CGM Ops control");
} else if (RACP_UUID.equals(uuid)){
Log.v(TAG, "RACP Ops control");
}
}
@Override
protected void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
if (characteristic.getUuid().equals(RACP_UUID)) {
Logger.a(mLogSession, "\"" + RecordAccessControlPointParser.parse(characteristic) + "\" sent");
} else { // uuid == CGM_OPS_CONTROL_POINT_UUID
Logger.a(mLogSession, "\"" + CGMSpecificOpsControlPointParser.parse(characteristic) + "\" sent");
}
}
@Override
protected void onCharacteristicIndicated(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
if (mLogSession != null)
Logger.a(mLogSession, RecordAccessControlPointParser.parse(characteristic));
@Override
public void onCharacteristicNotified(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
Logger.a(mLogSession, "\"" + CGMMeasurementParser.parse(characteristic) + "\" received");
// Record Access Control Point characteristic
int offset = 0;
final int opCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
offset += 2; // skip the operator
// CGM Measurement characteristic
final int cgmSize = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
if (cgmSize > 0) {
final float cgmValue = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, 2);
final int sequenceNumber = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 4);
final long timestamp = mSessionStartTime + (sequenceNumber * 60000L); // Sequence number is in minutes since Start Session
//This will send callback to CGMSActivity when new concentration value is received from CGMS device
final CGMSRecord cgmsRecord = new CGMSRecord(sequenceNumber, cgmValue, timestamp);
mRecords.put(cgmsRecord.sequenceNumber, cgmsRecord);
mCallbacks.onCGMValueReceived(gatt.getDevice(), cgmsRecord);
}
}
if (opCode == OP_CODE_NUMBER_OF_STORED_RECORDS_RESPONSE) {
// We've obtained the number of all records
final int number = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
@Override
protected void onCharacteristicIndicated(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
if (characteristic.getUuid().equals(RACP_UUID)) {
Logger.a(mLogSession, "\"" + RecordAccessControlPointParser.parse(characteristic) + "\" received");
mCallbacks.onNumberOfRecordsRequested(number);
// Record Access Control Point characteristic
int offset = 0;
final int opCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
offset += 2; // skip the operator
// Request the records
if (number > 0) {
final BluetoothGattCharacteristic racpCharacteristic = mRecordAccessControlPointCharacteristic;
setOpCode(racpCharacteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_ALL_RECORDS);
writeCharacteristic(racpCharacteristic);
} else {
mCallbacks.onOperationCompleted();
}
} else if (opCode == OP_CODE_RESPONSE_CODE) {
final int requestedOpCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
final int responseCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 1);
DebugLogger.d(TAG, "Response result for: " + requestedOpCode + " is: " + responseCode);
if (opCode == OP_CODE_NUMBER_OF_STORED_RECORDS_RESPONSE) {
// We've obtained the number of all records
final int number = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
switch (responseCode) {
case RESPONSE_SUCCESS:
if (!mAbort)
mCallbacks.onOperationCompleted();
else
mCallbacks.onOperationAborted();
break;
case RESPONSE_NO_RECORDS_FOUND:
mCallbacks.onOperationCompleted();
break;
case RESPONSE_OP_CODE_NOT_SUPPORTED:
mCallbacks.onOperationNotSupported();
break;
case RESPONSE_PROCEDURE_NOT_COMPLETED:
case RESPONSE_ABORT_UNSUCCESSFUL:
default:
mCallbacks.onOperationFailed();
break;
}
mAbort = false;
}
}
mCallbacks.onNumberOfRecordsRequested(gatt.getDevice(), number);
};
// Request the records
if (number > 0) {
final BluetoothGattCharacteristic racpCharacteristic = mRecordAccessControlPointCharacteristic;
setOpCode(racpCharacteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_ALL_RECORDS);
writeCharacteristic(racpCharacteristic);
} else {
mCallbacks.onOperationCompleted(gatt.getDevice());
}
} else if (opCode == OP_CODE_RESPONSE_CODE) {
final int requestedOpCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
final int responseCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 1);
DebugLogger.d(TAG, "Response result for: " + requestedOpCode + " is: " + responseCode);
/**
* Writes given operation parameters to the characteristic
*
* @param characteristic
* the characteristic to write. This must be the Record Access Control Point characteristic
* @param opCode
* the operation code
* @param operator
* the operator (see {@link #OPERATOR_NULL} and others
* @param params
* optional parameters (one for >=, <=, two for the range, none for other operators)
*/
private void setOpCode(final BluetoothGattCharacteristic characteristic, final int opCode, final int operator, final Integer... params) {
final int size = 2 + ((params.length > 0) ? 1 : 0) + params.length * 2; // 1 byte for opCode, 1 for operator, 1 for filter type (if parameters exists) and 2 for each parameter
characteristic.setValue(new byte[size]);
switch (responseCode) {
case RESPONSE_SUCCESS:
if (!mAbort)
mCallbacks.onOperationCompleted(gatt.getDevice());
else
mCallbacks.onOperationAborted(gatt.getDevice());
break;
case RESPONSE_NO_RECORDS_FOUND:
mCallbacks.onOperationCompleted(gatt.getDevice());
break;
case RESPONSE_OP_CODE_NOT_SUPPORTED:
mCallbacks.onOperationNotSupported(gatt.getDevice());
break;
case RESPONSE_PROCEDURE_NOT_COMPLETED:
case RESPONSE_ABORT_UNSUCCESSFUL:
default:
mCallbacks.onOperationFailed(gatt.getDevice());
break;
}
mAbort = false;
}
} else { // uuid == CGM_OPS_CONTROL_POINT_UUID
Logger.a(mLogSession, "\"" + CGMSpecificOpsControlPointParser.parse(characteristic) + "\" received");
}
}
};
// write the operation code
int offset = 0;
characteristic.setValue(opCode, BluetoothGattCharacteristic.FORMAT_UINT8, offset);
offset += 1;
/**
* Writes given operation parameters to the characteristic
*
* @param characteristic the characteristic to write. This must be the Record Access Control Point characteristic
* @param opCode the operation code
* @param operator the operator (see {@link #OPERATOR_NULL} and others
* @param params optional parameters (one for >=, <=, two for the range, none for other operators)
*/
private void setOpCode(final BluetoothGattCharacteristic characteristic, final int opCode, final int operator, final Integer... params) {
final int size = 2 + ((params.length > 0) ? 1 : 0) + params.length * 2; // 1 byte for opCode, 1 for operator, 1 for filter type (if parameters exists) and 2 for each parameter
characteristic.setValue(new byte[size]);
// write the operator. This is always present but may be equal to OPERATOR_NULL
characteristic.setValue(operator, BluetoothGattCharacteristic.FORMAT_UINT8, offset);
offset += 1;
// write the operation code
int offset = 0;
characteristic.setValue(opCode, BluetoothGattCharacteristic.FORMAT_UINT8, offset);
offset += 1;
// if parameters exists, append them. Parameters should be sorted from minimum to maximum. Currently only one or two params are allowed
if (params.length > 0) {
// our implementation use only sequence number as a filer type
characteristic.setValue(FILTER_TYPE_SEQUENCE_NUMBER, BluetoothGattCharacteristic.FORMAT_UINT8, offset);
offset += 1;
// write the operator. This is always present but may be equal to OPERATOR_NULL
characteristic.setValue(operator, BluetoothGattCharacteristic.FORMAT_UINT8, offset);
offset += 1;
for (final Integer i : params) {
characteristic.setValue(i, BluetoothGattCharacteristic.FORMAT_UINT16, offset);
offset += 2;
}
}
}
// if parameters exists, append them. Parameters should be sorted from minimum to maximum. Currently only one or two params are allowed
if (params.length > 0) {
// our implementation use only sequence number as a filer type
characteristic.setValue(FILTER_TYPE_SEQUENCE_NUMBER, BluetoothGattCharacteristic.FORMAT_UINT8, offset);
offset += 1;
/**
* Sends the request to obtain the last (most recent) record from glucose device. The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access
* Control Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of error.
*/
public void getLastRecord() {
if (mRecordAccessControlPointCharacteristic == null)
return;
for (final Integer i : params) {
characteristic.setValue(i, BluetoothGattCharacteristic.FORMAT_UINT16, offset);
offset += 2;
}
}
}
clear();
mCallbacks.onOperationStarted();
/**
* Returns a list of CGM records obtained from this device. The key in the array is the
*/
public SparseArray<CGMSRecord> getRecords() {
return mRecords;
}
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_LAST_RECORD);
writeCharacteristic(characteristic);
}
/**
* Clears the records list locally
*/
public void clear() {
mRecords.clear();
mCallbacks.onDatasetClear(mBluetoothDevice);
}
/**
* Returns all records as a sparse array where sequence number is the key.
*
* @return the records list
*/
public SparseArray<CGMSRecord> getRecords() {
return mRecords;
}
/**
* Sends the request to obtain the last (most recent) record from glucose device. The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access
* Control Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of error.
*/
public void getLastRecord() {
if (mRecordAccessControlPointCharacteristic == null)
return;
/**
* Clears the records list locally
*/
public void clear() {
mRecords.clear();
mCallbacks.onDatasetChanged();
}
clear();
mCallbacks.onOperationStarted(mBluetoothDevice);
/**
* Sends abort operation signal to the device
*/
public void abort() {
if (mRecordAccessControlPointCharacteristic == null)
return;
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_LAST_RECORD);
writeCharacteristic(characteristic);
}
mAbort = true;
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_ABORT_OPERATION, OPERATOR_NULL);
writeCharacteristic(characteristic);
}
/**
* Sends the request to obtain the first (oldest) record from glucose device. The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control
* Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of error.
*/
public void getFirstRecord() {
if (mRecordAccessControlPointCharacteristic == null)
return;
/**
* Sends the request to obtain the first (oldest) record from glucose device. The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control
* Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of error.
*/
public void getFirstRecord() {
if (mRecordAccessControlPointCharacteristic == null)
return;
clear();
mCallbacks.onOperationStarted(mBluetoothDevice);
clear();
mCallbacks.onOperationStarted();
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_FIRST_RECORD);
writeCharacteristic(characteristic);
}
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_FIRST_RECORD);
final LinkedList<Request> requests = new LinkedList<>();
writeCharacteristic(characteristic);
}
/**
* Sends abort operation signal to the device
*/
public void abort() {
if (mRecordAccessControlPointCharacteristic == null)
return;
/**
* Sends the request to obtain all records from glucose device. Initially we want to notify him/her about the number of the records so the {@link #OP_CODE_REPORT_NUMBER_OF_RECORDS} is send. The
* data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of
* error.
*/
public void getAllRecords() {
if (mRecordAccessControlPointCharacteristic == null)
return;
mAbort = true;
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_ABORT_OPERATION, OPERATOR_NULL);
writeCharacteristic(characteristic);
}
clear();
mCallbacks.onOperationStarted();
/**
* Sends the request to obtain all records from glucose device. Initially we want to notify him/her about the number of the records so the {@link #OP_CODE_REPORT_NUMBER_OF_RECORDS} is send. The
* data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of
* error.
*/
public void getAllRecords() {
if (mRecordAccessControlPointCharacteristic == null)
return;
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_REPORT_NUMBER_OF_RECORDS, OPERATOR_ALL_RECORDS);
writeCharacteristic(characteristic);
}
clear();
mCallbacks.onOperationStarted(mBluetoothDevice);
public void deleteAllRecords() {
if (mRecordAccessControlPointCharacteristic == null)
return;
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_REPORT_NUMBER_OF_RECORDS, OPERATOR_ALL_RECORDS);
writeCharacteristic(characteristic);
}
clear();
mCallbacks.onOperationStarted();
/**
* Sends the request to obtain all records from glucose device. Initially we want to notify him/her about the number of the records so the {@link #OP_CODE_REPORT_NUMBER_OF_RECORDS} is send. The
* data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of
* error.
*/
public void refreshRecords() {
if (mRecordAccessControlPointCharacteristic == null)
return;
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_DELETE_STORED_RECORDS, OPERATOR_ALL_RECORDS);
writeCharacteristic(characteristic);
}
if (mRecords.size() == 0) {
getAllRecords();
} else {
mCallbacks.onOperationStarted(mBluetoothDevice);
// obtain the last sequence number
final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1;
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_GREATER_THEN_OR_EQUAL, sequenceNumber);
writeCharacteristic(characteristic);
// Info:
// Operators OPERATOR_GREATER_THEN_OR_EQUAL, OPERATOR_LESS_THEN_OR_EQUAL and OPERATOR_RANGE are not supported by the CGMS sample from SDK
// The "Operation not supported" response will be received
}
}
public void deleteAllRecords() {
if (mRecordAccessControlPointCharacteristic == null)
return;
clear();
mCallbacks.onOperationStarted(mBluetoothDevice);
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_DELETE_STORED_RECORDS, OPERATOR_ALL_RECORDS);
writeCharacteristic(characteristic);
}
}

View File

@@ -22,6 +22,8 @@
package no.nordicsemi.android.nrftoolbox.cgms;
import android.bluetooth.BluetoothDevice;
import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
/**
@@ -29,26 +31,22 @@ import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
*/
public interface CGMSManagerCallbacks extends BleManagerCallbacks {
/**
* Called when new CGM value has been obtained from the sensor
*
* @param value
* the new value
* Called when new CGM value has been obtained from the sensor.
*/
public void onCGMValueReceived(float value, String timeStamp);
void onCGMValueReceived(final BluetoothDevice device, final CGMSRecord record);
void onOperationStarted(final BluetoothDevice device);
public void onOperationStarted();
void onOperationCompleted(final BluetoothDevice device);
public void onOperationCompleted();
void onOperationFailed(final BluetoothDevice device);
public void onOperationFailed();
void onOperationAborted(final BluetoothDevice device);
public void onOperationAborted();
void onOperationNotSupported(final BluetoothDevice device);
public void onOperationNotSupported();
void onDatasetClear(final BluetoothDevice device);
public void onDatasetChanged();
public void onNumberOfRecordsRequested(final int value);
void onNumberOfRecordsRequested(final BluetoothDevice device, final int value);
}

View File

@@ -3,31 +3,27 @@ package no.nordicsemi.android.nrftoolbox.cgms;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Calendar;
/**
* Created by rora on 02.09.2016.
*/
public class CGMSRecord implements Parcelable{
/** Record sequence number */
/** Record sequence number. */
protected int sequenceNumber;
/** The base time of the measurement */
protected Calendar time;
/** Time offset of the record */
protected String timeStamp;
protected float reading;
/** The base time of the measurement (start time + sequenceNumber of minutes). */
protected long timestamp;
/** The glucose concentration in mg/dL. */
protected float glucoseConcentration;
protected CGMSRecord(float cgmsValue, String timeStamp) {
sequenceNumber = 0;
this.timeStamp = timeStamp;
this.reading = cgmsValue;
protected CGMSRecord(int sequenceNumber, float glucoseConcentration, long timestamp) {
this.sequenceNumber = sequenceNumber;
this.glucoseConcentration = glucoseConcentration;
this.timestamp = timestamp;
}
protected CGMSRecord(Parcel in) {
sequenceNumber = in.readInt();
timeStamp = in.readString();
reading = in.readFloat();
this.sequenceNumber = in.readInt();
this.glucoseConcentration = in.readFloat();
this.timestamp = in.readLong();
}
public static final Creator<CGMSRecord> CREATOR = new Creator<CGMSRecord>() {
@@ -50,7 +46,7 @@ public class CGMSRecord implements Parcelable{
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(sequenceNumber);
parcel.writeString(timeStamp);
parcel.writeFloat(reading);
parcel.writeFloat(glucoseConcentration);
parcel.writeLong(timestamp);
}
}

View File

@@ -1,87 +1,82 @@
package no.nordicsemi.android.nrftoolbox.cgms;
import android.content.Context;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import no.nordicsemi.android.nrftoolbox.R;
/**
* Created by rora on 02.09.2016.
*/
public class CGMSRecordsAdapter extends BaseAdapter {
private final static SimpleDateFormat mTimeFormat = new SimpleDateFormat("dd.MM.YYYY HH:mm:ss", Locale.US);
private SparseArray<CGMSRecord> mRecords;
private LayoutInflater mInflator;
private Context context;
private List<CGMSRecord> mRecords;
private LayoutInflater mInflater;
public CGMSRecordsAdapter(Context context) {
super();
mRecords = new SparseArray<>();
this.context = context;
mInflator = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public CGMSRecordsAdapter(final Context context) {
mRecords = new ArrayList<>();
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return mRecords.size();
}
@Override
public int getCount() {
return mRecords.size();
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.activity_feature_cgms_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.concentration = (TextView) convertView.findViewById(R.id.cgms_concentration);
viewHolder.time = (TextView) convertView.findViewById(R.id.time);
viewHolder.details = (TextView) convertView.findViewById(R.id.details);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
ViewHolder viewHolder;
if (convertView == null) {
convertView = mInflator.inflate(R.layout.activity_feature_cgms_item, null);
viewHolder = new ViewHolder();
viewHolder.concentration = (TextView) convertView.findViewById(R.id.cgms_concentration);
viewHolder.time = (TextView) convertView.findViewById(R.id.time);
viewHolder.details = (TextView) convertView.findViewById(R.id.details);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final CGMSRecord cgmsRecord = mRecords.get(position);
viewHolder.concentration.setText(String.valueOf(cgmsRecord.glucoseConcentration));
viewHolder.details.setText(viewHolder.details.getResources().getString(R.string.cgms_details, cgmsRecord.sequenceNumber));
viewHolder.time.setText(mTimeFormat.format(new Date(cgmsRecord.timestamp)));
final CGMSRecord cgmsRecord = mRecords.get(position);
final String concentration = String.valueOf(cgmsRecord.reading);
return convertView;
}
if (concentration != null && concentration.length() > 0) {
viewHolder.concentration.setText(concentration /*+ " " + context.getString(R.string.cgms_value_unit*/);
viewHolder.time.setText(cgmsRecord.timeStamp);
}
public void addItem(final CGMSRecord record) {
mRecords.add(record);
}
return convertView;
}
public void clear() {
mRecords.clear();
}
public void addItem(CGMSRecord record) {
mRecords.put(mRecords.size(), record);
}
public SparseArray<CGMSRecord> getValues() {
return mRecords;
}
public void clear() {
mRecords.clear();
}
static class ViewHolder {
TextView time;
TextView details;
TextView concentration;
}
private static class ViewHolder {
TextView time;
TextView details;
TextView concentration;
}
}

View File

@@ -3,6 +3,7 @@ package no.nordicsemi.android.nrftoolbox.cgms;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -22,7 +23,8 @@ import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
*/
public class CGMService extends BleProfileService implements CGMSManagerCallbacks {
private static final String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.cgms.ACTION_DISCONNECT";
public static final String BROADCAST_CGMS_VALUES = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_CGMS_VALUES";
public static final String BROADCAST_NEW_CGMS_VALUE = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_NEW_CGMS_VALUE";
public static final String BROADCAST_DATA_SET_CLEAR = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_DATA_SET_CLEAR";
public static final String OPERATION_STARTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_STARTED";
public static final String OPERATION_COMPLETED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_COMPLETED";
public static final String OPERATION_SUPPORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_SUPPORTED";
@@ -30,7 +32,6 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
public static final String OPERATION_FAILED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_FAILED";
public static final String OPERATION_ABORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_ABORTED";
public static final String EXTRA_CGMS_RECORD = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_CGMS_RECORD";
public static final String BROADCAST_DATA_SET_CHANGED = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_DATA_SET_CHANGED";
public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_DATA";
private final static int NOTIFICATION_ID = 229;
@@ -39,54 +40,32 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
private CGMSManager mManager;
private final LocalBinder mBinder = new CGMSBinder();
private SparseArray<CGMSRecord> mRecords = new SparseArray<>();
/**
* This local binder is an interface for the bonded activity to operate with the RSC sensor
*/
public class CGMSBinder extends LocalBinder {
public SparseArray<CGMSRecord> getCgmsRecords() {
return mRecords;
}
/**
* Sends the request to obtain the last (most recent) record from glucose device. The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access
* Control Point indication with status code ({@link CGMSManager#RESPONSE_SUCCESS} or other in case of error.
*/
public void getLastRecord() {
clear();
if(mManager != null)
mManager.getLastRecord();
}
/**
* Returns all records as a sparse array where sequence number is the key.
*
* @return the records list
*/
public SparseArray<CGMSRecord> getRecords() {
return mRecords;
return mManager.getRecords();
}
/**
* Clears the records list locally
*/
public void clear() {
mRecords.clear();
if (mManager != null)
mManager.clear();
}
/**
* Sends abort operation signal to the device
*/
public void abort() {
if(mManager != null)
mManager.abort();
}
/**
* Sends the request to obtain the first (oldest) record from glucose device. The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control
* Sends the request to obtain the first (oldest) record from glucose device.
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control
* Point indication with status code ({@link CGMSManager# RESPONSE_SUCCESS} or other in case of error.
*/
public void getFirstRecord() {
@@ -95,18 +74,48 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
}
/**
* Sends the request to obtain all records from glucose device. Initially we want to notify him/her about the number of the records so the {@link CGMSManager#OP_CODE_REPORT_NUMBER_OF_RECORDS} is send. The
* data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control Point indication with status code ({@link CGMSManager#RESPONSE_SUCCESS} or other in case of
* error.
* Sends the request to obtain the last (most recent) record from glucose device.
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access
* Control Point indication with status code ({@link CGMSManager#RESPONSE_SUCCESS} or other in case of error.
*/
public void getLastRecord() {
if(mManager != null)
mManager.getLastRecord();
}
/**
* Sends the request to obtain all records from glucose device.
* Initially we want to notify user about the number of the records so the {@link CGMSManager#OP_CODE_REPORT_NUMBER_OF_RECORDS} is send.
* The data will be returned to Glucose Measurement characteristic as a series of notifications followed by Record Access Control Point
* indication with status code ({@link CGMSManager#RESPONSE_SUCCESS} or other in case of error.
*/
public void getAllRecords() {
clear();
if(mManager != null)
mManager.getAllRecords();
}
public void deleteAllRecords() {
/**
* Sends the request to obtain all records from glucose device with sequence number greater than the last one already obtained.
* The data will be returned to Glucose Measurement characteristic as a series of notifications followed by Record Access Control Point
* indication with status code ({@link CGMSManager#RESPONSE_SUCCESS} or other in case of error.
*/
public void refreshRecords() {
if (mManager != null)
mManager.refreshRecords();
}
/**
* Sends abort operation signal to the device
*/
public void abort() {
if(mManager != null)
mManager.abort();
}
/**
* Sends Delete op code with All stored records parameter. This method may not be supported by the SDK sample.
*/
public void deleteAllRecords() {
if(mManager != null)
mManager.deleteAllRecords();
}
@@ -212,56 +221,62 @@ public class CGMService extends BleProfileService implements CGMSManagerCallback
};
@Override
public void onCGMValueReceived(float value, String timeStamp) {
final Intent broadcast = new Intent(BROADCAST_CGMS_VALUES);
CGMSRecord cgmsRecord = new CGMSRecord(value, timeStamp);
broadcast.putExtra(EXTRA_CGMS_RECORD, cgmsRecord);
public void onCGMValueReceived(final BluetoothDevice device, final CGMSRecord record) {
final Intent broadcast = new Intent(BROADCAST_NEW_CGMS_VALUE);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_CGMS_RECORD, record);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
mRecords.put(mRecords.size(), cgmsRecord);
}
@Override
public void onOperationStarted() {
public void onOperationStarted(final BluetoothDevice device) {
final Intent broadcast = new Intent(OPERATION_STARTED);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_DATA, true);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onOperationCompleted() {
public void onOperationCompleted(final BluetoothDevice device) {
final Intent broadcast = new Intent(OPERATION_COMPLETED);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_DATA, true);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onOperationFailed() {
public void onOperationFailed(final BluetoothDevice device) {
final Intent broadcast = new Intent(OPERATION_FAILED);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_DATA, true);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onOperationAborted() {
public void onOperationAborted(final BluetoothDevice device) {
final Intent broadcast = new Intent(OPERATION_ABORTED);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_DATA, true);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onOperationNotSupported() {
public void onOperationNotSupported(final BluetoothDevice device) {
final Intent broadcast = new Intent(OPERATION_NOT_SUPPORTED);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_DATA, false);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onDatasetChanged() {
public void onDatasetClear(final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_DATA_SET_CLEAR);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onNumberOfRecordsRequested(int value) {
public void onNumberOfRecordsRequested(final BluetoothDevice device, int value) {
showToast(getString(R.string.gls_progress, value));
}
}

View File

@@ -22,6 +22,7 @@
package no.nordicsemi.android.nrftoolbox.csc;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -33,6 +34,7 @@ import android.support.v4.content.LocalBroadcastManager;
import android.view.Menu;
import android.widget.TextView;
import java.util.Locale;
import java.util.UUID;
import no.nordicsemi.android.nrftoolbox.R;
@@ -172,7 +174,7 @@ public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBi
}
@Override
public void onServicesDiscovered(final boolean optionalServicesFound) {
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
// not used
}
@@ -186,35 +188,35 @@ public class CSCActivity extends BleProfileServiceReadyActivity<CSCService.CSCBi
// pass through intended
case SettingsFragment.SETTINGS_UNIT_M_S:
if (distance < 1000) { // 1 km in m
mDistanceView.setText(String.format("%.0f", distance));
mDistanceView.setText(String.format(Locale.US, "%.0f", distance));
mDistanceUnitView.setText(R.string.csc_distance_unit_m);
} else {
mDistanceView.setText(String.format("%.2f", distance / 1000.0f));
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 1000.0f));
mDistanceUnitView.setText(R.string.csc_distance_unit_km);
}
mTotalDistanceView.setText(String.format("%.2f", totalDistance / 1000.0f));
mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1000.0f));
break;
case SettingsFragment.SETTINGS_UNIT_MPH:
speed = speed * 2.2369f;
if (distance < 1760) { // 1 mile in yrs
mDistanceView.setText(String.format("%.0f", distance));
mDistanceView.setText(String.format(Locale.US, "%.0f", distance));
mDistanceUnitView.setText(R.string.csc_distance_unit_yd);
} else {
mDistanceView.setText(String.format("%.2f", distance / 1760.0f));
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 1760.0f));
mDistanceUnitView.setText(R.string.csc_distance_unit_mile);
}
mTotalDistanceView.setText(String.format("%.2f", totalDistance / 1609.31f));
mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1609.31f));
break;
}
mSpeedView.setText(String.format("%.1f", speed));
mSpeedView.setText(String.format(Locale.US, "%.1f", speed));
}
private void onGearRatioUpdate(final float ratio, final int cadence) {
mGearRatioView.setText(String.format("%.1f", ratio));
mCadenceView.setText(String.format("%d", cadence));
mGearRatioView.setText(String.format(Locale.US, "%.1f", ratio));
mCadenceView.setText(String.format(Locale.US, "%d", cadence));
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {

View File

@@ -63,7 +63,7 @@ public class CSCManager extends BleManager<CSCManagerCallbacks> {
@Override
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
requests.push(Request.newEnableNotificationsRequest(mCSCMeasurementCharacteristic));
requests.add(Request.newEnableNotificationsRequest(mCSCMeasurementCharacteristic));
return requests;
}
@@ -83,8 +83,7 @@ public class CSCManager extends BleManager<CSCManagerCallbacks> {
@Override
public void onCharacteristicNotified(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
if (mLogSession != null)
Logger.a(mLogSession, CSCMeasurementParser.parse(characteristic));
Logger.a(mLogSession, "\"" + CSCMeasurementParser.parse(characteristic) + "\" received");
// Decode the new data
int offset = 0;
@@ -102,7 +101,7 @@ public class CSCManager extends BleManager<CSCManagerCallbacks> {
offset += 2;
// Notify listener about the new measurement
mCallbacks.onWheelMeasurementReceived(wheelRevolutions, lastWheelEventTime);
mCallbacks.onWheelMeasurementReceived(gatt.getDevice(), wheelRevolutions, lastWheelEventTime);
}
if (crankRevPreset) {
@@ -113,7 +112,7 @@ public class CSCManager extends BleManager<CSCManagerCallbacks> {
// offset += 2;
// Notify listener about the new measurement
mCallbacks.onCrankMeasurementReceived(crankRevolutions, lastCrankEventTime);
mCallbacks.onCrankMeasurementReceived(gatt.getDevice(), crankRevolutions, lastCrankEventTime);
}
}
};

View File

@@ -21,12 +21,14 @@
*/
package no.nordicsemi.android.nrftoolbox.csc;
import android.bluetooth.BluetoothDevice;
import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
public interface CSCManagerCallbacks extends BleManagerCallbacks {
public static final int NOT_AVAILABLE = -1;
int NOT_AVAILABLE = -1;
public void onWheelMeasurementReceived(final int wheelRevolutions, final int wheelCrankEventTime);
void onWheelMeasurementReceived(final BluetoothDevice device, final int wheelRevolutions, final int wheelCrankEventTime);
public void onCrankMeasurementReceived(final int crankRevolutions, final int lastCrankEventTime);
void onCrankMeasurementReceived(final BluetoothDevice device, final int crankRevolutions, final int lastCrankEventTime);
}

View File

@@ -25,6 +25,7 @@ package no.nordicsemi.android.nrftoolbox.csc;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -126,7 +127,7 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
}
@Override
public void onWheelMeasurementReceived(final int wheelRevolutions, final int lastWheelEventTime) {
public void onWheelMeasurementReceived(final BluetoothDevice device, final int wheelRevolutions, final int lastWheelEventTime) {
Logger.a(getLogSession(), "Wheel rev: " + wheelRevolutions + "\nLast wheel event time: " + lastWheelEventTime + " ms");
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
@@ -151,6 +152,7 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
mWheelCadence = (wheelRevolutions - mLastWheelRevolutions) * 60.0f / timeDifference;
final Intent broadcast = new Intent(BROADCAST_WHEEL_DATA);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_SPEED, speed);
broadcast.putExtra(EXTRA_DISTANCE, distance);
broadcast.putExtra(EXTRA_TOTAL_DISTANCE, totalDistance);
@@ -161,7 +163,7 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
}
@Override
public void onCrankMeasurementReceived(int crankRevolutions, int lastCrankEventTime) {
public void onCrankMeasurementReceived(final BluetoothDevice device, int crankRevolutions, int lastCrankEventTime) {
Logger.a(getLogSession(), "Crank rev: " + crankRevolutions + "\nLast crank event time: " + lastCrankEventTime + " ms");
if (mLastCrankEventTime == lastCrankEventTime)
@@ -179,6 +181,7 @@ public class CSCService extends BleProfileService implements CSCManagerCallbacks
final float gearRatio = mWheelCadence / crankCadence;
final Intent broadcast = new Intent(BROADCAST_CRANK_DATA);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_GEAR_RATIO, gearRatio);
broadcast.putExtra(EXTRA_CADENCE, (int) crankCadence);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);

View File

@@ -21,6 +21,7 @@
*/
package no.nordicsemi.android.nrftoolbox.gls;
import android.bluetooth.BluetoothDevice;
import android.os.Bundle;
import android.util.SparseArray;
import android.view.MenuInflater;
@@ -158,46 +159,46 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
}
@Override
public void onDeviceDisconnected() {
super.onDeviceDisconnected();
public void onDeviceDisconnected(final BluetoothDevice device) {
super.onDeviceDisconnected(device);
setOperationInProgress(false);
}
@Override
public void onOperationStarted() {
public void onOperationStarted(final BluetoothDevice device) {
setOperationInProgress(true);
}
@Override
public void onOperationCompleted() {
public void onOperationCompleted(final BluetoothDevice device) {
setOperationInProgress(false);
}
@Override
public void onOperationAborted() {
public void onOperationAborted(final BluetoothDevice device) {
setOperationInProgress(false);
}
@Override
public void onOperationNotSupported() {
public void onOperationNotSupported(final BluetoothDevice device) {
setOperationInProgress(false);
showToast(R.string.gls_operation_not_supported);
}
@Override
public void onOperationFailed() {
public void onOperationFailed(final BluetoothDevice device) {
setOperationInProgress(false);
showToast(R.string.gls_operation_failed);
}
@Override
public void onError(final String message, final int errorCode) {
super.onError(message, errorCode);
onOperationFailed();
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
super.onError(device, message, errorCode);
onOperationFailed(device);
}
@Override
public void onDatasetChanged() {
public void onDatasetChanged(final BluetoothDevice device) {
runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -215,7 +216,7 @@ public class GlucoseActivity extends BleProfileExpandableListActivity implements
}
@Override
public void onNumberOfRecordsRequested(final int value) {
public void onNumberOfRecordsRequested(final BluetoothDevice device, final int value) {
showToast(getString(R.string.gls_progress, value));
}
}

View File

@@ -129,10 +129,10 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
@Override
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
requests.push(Request.newEnableNotificationsRequest(mGlucoseMeasurementCharacteristic));
requests.add(Request.newEnableNotificationsRequest(mGlucoseMeasurementCharacteristic));
if (mGlucoseMeasurementContextCharacteristic != null)
requests.push(Request.newEnableNotificationsRequest(mGlucoseMeasurementContextCharacteristic));
requests.push(Request.newEnableIndicationsRequest(mRecordAccessControlPointCharacteristic));
requests.add(Request.newEnableNotificationsRequest(mGlucoseMeasurementContextCharacteristic));
requests.add(Request.newEnableIndicationsRequest(mRecordAccessControlPointCharacteristic));
return requests;
}
@@ -160,12 +160,16 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
}
@Override
public void onCharacteristicNotified(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
protected void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
Logger.a(mLogSession, "\"" + RecordAccessControlPointParser.parse(characteristic) + "\" sent");
}
@Override
public void onCharacteristicNotified(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
final UUID uuid = characteristic.getUuid();
if (GM_CHARACTERISTIC.equals(uuid)) {
if (mLogSession != null)
Logger.a(mLogSession, GlucoseMeasurementParser.parse(characteristic));
Logger.a(mLogSession, "\"" + GlucoseMeasurementParser.parse(characteristic) + "\" received");
int offset = 0;
final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
@@ -237,12 +241,11 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
// if there is no context information following the measurement data, notify callback about the new record
if (!contextInfoFollows)
mCallbacks.onDatasetChanged();
mCallbacks.onDatasetChanged(gatt.getDevice());
}
});
} else if (GM_CONTEXT_CHARACTERISTIC.equals(uuid)) {
if (mLogSession != null)
Logger.a(mLogSession, GlucoseMeasurementContextParser.parse(characteristic));
Logger.a(mLogSession, "\"" + GlucoseMeasurementContextParser.parse(characteristic) + "\" received");
int offset = 0;
final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
@@ -308,14 +311,13 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
}
// notify callback about the new record
mCallbacks.onDatasetChanged();
mCallbacks.onDatasetChanged(gatt.getDevice());
}
}
@Override
protected void onCharacteristicIndicated(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
if (mLogSession != null)
Logger.a(mLogSession, RecordAccessControlPointParser.parse(characteristic));
Logger.a(mLogSession, "\"" + RecordAccessControlPointParser.parse(characteristic) + "\" received");
// Record Access Control Point characteristic
int offset = 0;
@@ -326,7 +328,7 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
// We've obtained the number of all records
final int number = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
mCallbacks.onNumberOfRecordsRequested(number);
mCallbacks.onNumberOfRecordsRequested(gatt.getDevice(), number);
// Request the records
if (number > 0) {
@@ -334,7 +336,7 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
setOpCode(racpCharacteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_ALL_RECORDS);
writeCharacteristic(racpCharacteristic);
} else {
mCallbacks.onOperationCompleted();
mCallbacks.onOperationCompleted(gatt.getDevice());
}
} else if (opCode == OP_CODE_RESPONSE_CODE) {
final int requestedOpCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
@@ -344,20 +346,20 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
switch (responseCode) {
case RESPONSE_SUCCESS:
if (!mAbort)
mCallbacks.onOperationCompleted();
mCallbacks.onOperationCompleted(gatt.getDevice());
else
mCallbacks.onOperationAborted();
mCallbacks.onOperationAborted(gatt.getDevice());
break;
case RESPONSE_NO_RECORDS_FOUND:
mCallbacks.onOperationCompleted();
mCallbacks.onOperationCompleted(gatt.getDevice());
break;
case RESPONSE_OP_CODE_NOT_SUPPORTED:
mCallbacks.onOperationNotSupported();
mCallbacks.onOperationNotSupported(gatt.getDevice());
break;
case RESPONSE_PROCEDURE_NOT_COMPLETED:
case RESPONSE_ABORT_UNSUCCESSFUL:
default:
mCallbacks.onOperationFailed();
mCallbacks.onOperationFailed(gatt.getDevice());
break;
}
mAbort = false;
@@ -416,7 +418,7 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
*/
public void clear() {
mRecords.clear();
mCallbacks.onDatasetChanged();
mCallbacks.onDatasetChanged(mBluetoothDevice);
}
/**
@@ -428,7 +430,7 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
return;
clear();
mCallbacks.onOperationStarted();
mCallbacks.onOperationStarted(mBluetoothDevice);
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_LAST_RECORD);
@@ -444,7 +446,7 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
return;
clear();
mCallbacks.onOperationStarted();
mCallbacks.onOperationStarted(mBluetoothDevice);
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_FIRST_RECORD);
@@ -461,7 +463,7 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
return;
clear();
mCallbacks.onOperationStarted();
mCallbacks.onOperationStarted(mBluetoothDevice);
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_REPORT_NUMBER_OF_RECORDS, OPERATOR_ALL_RECORDS);
@@ -483,7 +485,7 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
if (mRecords.size() == 0) {
getAllRecords();
} else {
mCallbacks.onOperationStarted();
mCallbacks.onOperationStarted(mBluetoothDevice);
// obtain the last sequence number
final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1;
@@ -519,7 +521,7 @@ public class GlucoseManager extends BleManager<GlucoseManagerCallbacks> {
return;
clear();
mCallbacks.onOperationStarted();
mCallbacks.onOperationStarted(mBluetoothDevice);
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
setOpCode(characteristic, OP_CODE_DELETE_STORED_RECORDS, OPERATOR_ALL_RECORDS);

View File

@@ -21,23 +21,22 @@
*/
package no.nordicsemi.android.nrftoolbox.gls;
import android.bluetooth.BluetoothDevice;
import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
public interface GlucoseManagerCallbacks extends BleManagerCallbacks {
public static final int UNIT_mmHG = 0;
public static final int UNIT_kPa = 1;
void onOperationStarted(final BluetoothDevice device);
public void onOperationStarted();
void onOperationCompleted(final BluetoothDevice device);
public void onOperationCompleted();
void onOperationFailed(final BluetoothDevice device);
public void onOperationFailed();
void onOperationAborted(final BluetoothDevice device);
public void onOperationAborted();
void onOperationNotSupported(final BluetoothDevice device);
public void onOperationNotSupported();
void onDatasetChanged(final BluetoothDevice device);
public void onDatasetChanged();
public void onNumberOfRecordsRequested(final int value);
void onNumberOfRecordsRequested(final BluetoothDevice device, final int value);
}

View File

@@ -210,29 +210,29 @@ public class HRSActivity extends BleProfileActivity implements HRSManagerCallbac
}
@Override
public void onServicesDiscovered(final boolean optionalServicesFound) {
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
// this may notify user or show some views
}
@Override
public void onDeviceReady() {
public void onDeviceReady(final BluetoothDevice device) {
startShowGraph();
}
@Override
public void onHRSensorPositionFound(final String position) {
public void onHRSensorPositionFound(final BluetoothDevice device, final String position) {
setHRSPositionOnView(position);
}
@Override
public void onHRValueReceived(int value) {
public void onHRValueReceived(final BluetoothDevice device, int value) {
mHrmValue = value;
setHRSValueOnView(mHrmValue);
}
@Override
public void onDeviceDisconnected() {
super.onDeviceDisconnected();
public void onDeviceDisconnected(final BluetoothDevice device) {
super.onDeviceDisconnected(device);
runOnUiThread(new Runnable() {
@Override
public void run() {

View File

@@ -77,8 +77,8 @@ public class HRSManager extends BleManager<HRSManagerCallbacks> {
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
if (mHRLocationCharacteristic != null)
requests.push(Request.newReadRequest(mHRLocationCharacteristic));
requests.push(Request.newEnableNotificationsRequest(mHRCharacteristic));
requests.add(Request.newReadRequest(mHRLocationCharacteristic));
requests.add(Request.newEnableNotificationsRequest(mHRCharacteristic));
return requests;
}
@@ -102,12 +102,11 @@ public class HRSManager extends BleManager<HRSManagerCallbacks> {
@Override
public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
if (mLogSession != null)
Logger.a(mLogSession, BodySensorLocationParser.parse(characteristic));
Logger.a(mLogSession, "\"" + BodySensorLocationParser.parse(characteristic) + "\" received");
final String sensorPosition = getBodySensorPosition(characteristic.getValue()[0]);
//This will send callback to HRSActivity when HR sensor position on body is found in HR device
mCallbacks.onHRSensorPositionFound(sensorPosition);
mCallbacks.onHRSensorPositionFound(gatt.getDevice(), sensorPosition);
}
@Override
@@ -118,8 +117,7 @@ public class HRSManager extends BleManager<HRSManagerCallbacks> {
@Override
public void onCharacteristicNotified(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
if (mLogSession != null)
Logger.a(mLogSession, HeartRateMeasurementParser.parse(characteristic));
Logger.a(mLogSession, "\"" + HeartRateMeasurementParser.parse(characteristic) + "\" received");
int hrValue;
if (isHeartRateInUINT16(characteristic.getValue()[0])) {
@@ -128,7 +126,7 @@ public class HRSManager extends BleManager<HRSManagerCallbacks> {
hrValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 1);
}
//This will send callback to HRSActivity when new HR value is received from HR device
mCallbacks.onHRValueReceived(hrValue);
mCallbacks.onHRValueReceived(gatt.getDevice(), hrValue);
}
};

View File

@@ -21,23 +21,27 @@
*/
package no.nordicsemi.android.nrftoolbox.hrs;
import android.bluetooth.BluetoothDevice;
import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
public interface HRSManagerCallbacks extends BleManagerCallbacks {
/**
* Called when the sensor position information has been obtained from the sensor
*
*
* @param device the bluetooth device from which the value was obtained
* @param position
* the sensor position
*/
public void onHRSensorPositionFound(String position);
void onHRSensorPositionFound(final BluetoothDevice device, String position);
/**
* Called when new Heart Rate value has been obtained from the sensor
*
*
* @param device the bluetooth device from which the value was obtained
* @param value
* the new value
*/
public void onHRValueReceived(int value);
void onHRValueReceived(final BluetoothDevice device, int value);
}

View File

@@ -21,6 +21,7 @@
*/
package no.nordicsemi.android.nrftoolbox.hts;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -179,7 +180,7 @@ public class HTSActivity extends BleProfileServiceReadyActivity<HTSService.RSCBi
}
@Override
public void onServicesDiscovered(boolean optionalServicesFound) {
public void onServicesDiscovered(final BluetoothDevice device, boolean optionalServicesFound) {
// this may notify user or show some views
}

View File

@@ -73,7 +73,7 @@ public class HTSManager extends BleManager<HTSManagerCallbacks> {
@Override
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
requests.push(Request.newEnableIndicationsRequest(mHTCharacteristic));
requests.add(Request.newEnableIndicationsRequest(mHTCharacteristic));
return requests;
}
@@ -93,12 +93,11 @@ public class HTSManager extends BleManager<HTSManagerCallbacks> {
@Override
public void onCharacteristicIndicated(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
if (mLogSession != null)
Logger.a(mLogSession, TemperatureMeasurementParser.parse(characteristic));
Logger.a(mLogSession, "\"" + TemperatureMeasurementParser.parse(characteristic) + "\" received");
try {
final double tempValue = decodeTemperature(characteristic.getValue());
mCallbacks.onHTValueReceived(tempValue);
mCallbacks.onHTValueReceived(gatt.getDevice(), tempValue);
} catch (Exception e) {
DebugLogger.e(TAG, "Invalid temperature value", e);
}

View File

@@ -21,6 +21,8 @@
*/
package no.nordicsemi.android.nrftoolbox.hts;
import android.bluetooth.BluetoothDevice;
import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
/**
@@ -30,10 +32,11 @@ public interface HTSManagerCallbacks extends BleManagerCallbacks {
/**
* Called when Health Thermometer value has been received
*
*
* @param device the bluetooth device from which the value was obtained
* @param value
* the new value
*/
public void onHTValueReceived(double value);
void onHTValueReceived(final BluetoothDevice device, double value);
}

View File

@@ -25,6 +25,7 @@ package no.nordicsemi.android.nrftoolbox.hts;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -106,8 +107,9 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
}
@Override
public void onHTValueReceived(final double value) {
public void onHTValueReceived(final BluetoothDevice device, final double value) {
final Intent broadcast = new Intent(BROADCAST_HTS_MEASUREMENT);
broadcast.putExtra(EXTRA_DEVICE, device);
broadcast.putExtra(EXTRA_TEMPERATURE, value);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
@@ -169,5 +171,4 @@ public class HTSService extends BleProfileService implements HTSManagerCallbacks
stopSelf();
}
};
}

View File

@@ -0,0 +1,183 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.nrftoolbox.parser;
import android.bluetooth.BluetoothGattCharacteristic;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class CGMMeasurementParser {
private static final int FLAGS_CGM_TREND_INFO_PRESENT = 1;
private static final int FLAGS_CGM_QUALITY_PRESENT = 1 << 1;
private static final int FLAGS_SENSOR_STATUS_ANNUNCIATION_WARNING_OCTET_PRESENT = 1 << 2;
private static final int FLAGS_SENSOR_STATUS_ANNUNCIATION_CAL_TEMP_OCTET_PRESENT = 1 << 3;
private static final int FLAGS_SENSOR_STATUS_ANNUNCIATION_STATUS_OCTET_PRESENT = 1 << 4;
private static final int SSA_SESSION_STOPPED = 1;
private static final int SSA_DEVICE_BATTERY_LOW = 1 << 1;
private static final int SSA_SENSOR_TYPE_INCORRECT = 1 << 2;
private static final int SSA_SENSOR_MALFUNCTION = 1 << 3;
private static final int SSA_DEVICE_SPEC_ALERT = 1 << 4;
private static final int SSA_GENERAL_DEVICE_FAULT = 1 << 5;
private static final int SSA_TIME_SYNC_REQUIRED = 1 << 8;
private static final int SSA_CALIBRATION_NOT_ALLOWED = 1 << 9;
private static final int SSA_CALIBRATION_RECOMMENDED = 1 << 10;
private static final int SSA_CALIBRATION_REQUIRED = 1 << 11;
private static final int SSA_SENSOR_TEMP_TOO_HIGH = 1 << 12;
private static final int SSA_SENSOR_TEMP_TOO_LOW = 1 << 13;
private static final int SSA_RESULT_LOWER_THAN_PATIENT_LOW_LEVEL = 1 << 16;
private static final int SSA_RESULT_HIGHER_THAN_PATIENT_HIGH_LEVEL = 1 << 17;
private static final int SSA_RESULT_LOWER_THAN_HYPO_LEVEL = 1 << 18;
private static final int SSA_RESULT_HIGHER_THAN_HYPER_LEVEL = 1 << 19;
private static final int SSA_SENSOR_RATE_OF_DECREASE_EXCEEDED = 1 << 20;
private static final int SSA_SENSOR_RATE_OF_INCREASE_EXCEEDED = 1 << 21;
private static final int SSA_RESULT_LOWER_THAN_DEVICE_CAN_PROCESS = 1 << 22;
private static final int SSA_RESULT_HIGHER_THAN_DEVICE_CAN_PROCESS = 1 << 23;
public static String parse(final BluetoothGattCharacteristic characteristic) {
int offset = 0;
// Read size and flags bytes
final int size = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);
final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);
/*
* false CGM Trend Information is not preset
* true CGM Trend Information is preset
*/
final boolean cgmTrendInformationPresent = (flags & FLAGS_CGM_TREND_INFO_PRESENT) > 0;
/*
* false CGM Quality is not preset
* true CGM Quality is preset
*/
final boolean cgmQualityPresent = (flags & FLAGS_CGM_QUALITY_PRESENT) > 0;
/*
* false Sensor Status Annunciation - Warning-Octet is not preset
* true Sensor Status Annunciation - Warning-Octet is preset
*/
final boolean ssaWarningOctetPresent = (flags & FLAGS_SENSOR_STATUS_ANNUNCIATION_WARNING_OCTET_PRESENT) > 0;
/*
* false Sensor Status Annunciation - Calibration/Temp-Octet is not preset
* true Sensor Status Annunciation - Calibration/Temp-Octet is preset
*/
final boolean ssaCalTempOctetPresent = (flags & FLAGS_SENSOR_STATUS_ANNUNCIATION_CAL_TEMP_OCTET_PRESENT) > 0;
/*
* false Sensor Status Annunciation - Status-Octet is not preset
* true Sensor Status Annunciation - Status-Octet is preset
*/
final boolean ssaStatusOctetPresent = (flags & FLAGS_SENSOR_STATUS_ANNUNCIATION_STATUS_OCTET_PRESENT) > 0;
// Read CGM Glucose Concentration
final float glucoseConcentration = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset);
offset += 2;
// Read time offset
final int timeOffset = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
offset += 2;
final StringBuilder builder = new StringBuilder();
builder.append("Glucose concentration: ").append(glucoseConcentration).append(" mg/dL\n");
builder.append("Sequence number: ").append(timeOffset).append(" (minutes since start)\n");
if (ssaWarningOctetPresent) {
final int ssaWarningOctet = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);
builder.append("Warnings:\n");
if ((ssaWarningOctet & SSA_SESSION_STOPPED) > 0)
builder.append("- Session Stopped\n");
if ((ssaWarningOctet & SSA_DEVICE_BATTERY_LOW) > 0)
builder.append("- Device Battery Low\n");
if ((ssaWarningOctet & SSA_SENSOR_TYPE_INCORRECT) > 0)
builder.append("- Sensor Type Incorrect\n");
if ((ssaWarningOctet & SSA_SENSOR_MALFUNCTION) > 0)
builder.append("- Sensor Malfunction\n");
if ((ssaWarningOctet & SSA_DEVICE_SPEC_ALERT) > 0)
builder.append("- Device Specific Alert\n");
if ((ssaWarningOctet & SSA_GENERAL_DEVICE_FAULT) > 0)
builder.append("- General Device Fault\n");
}
if (ssaCalTempOctetPresent) {
final int ssaCalTempOctet = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);
builder.append("Cal/Temp Info:\n");
if ((ssaCalTempOctet & SSA_TIME_SYNC_REQUIRED) > 0)
builder.append("- Time Synchronization Required\n");
if ((ssaCalTempOctet & SSA_CALIBRATION_NOT_ALLOWED) > 0)
builder.append("- Calibration Not Allowed\n");
if ((ssaCalTempOctet & SSA_CALIBRATION_RECOMMENDED) > 0)
builder.append("- Calibration Recommended\n");
if ((ssaCalTempOctet & SSA_CALIBRATION_REQUIRED) > 0)
builder.append("- Calibration Required\n");
if ((ssaCalTempOctet & SSA_SENSOR_TEMP_TOO_HIGH) > 0)
builder.append("- Sensor Temp Too High\n");
if ((ssaCalTempOctet & SSA_SENSOR_TEMP_TOO_LOW) > 0)
builder.append("- Sensor Temp Too Low\n");
}
if (ssaStatusOctetPresent) {
final int ssaStatusOctet = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);
builder.append("Status:\n");
if ((ssaStatusOctet & SSA_RESULT_LOWER_THAN_PATIENT_LOW_LEVEL) > 0)
builder.append("- Result Lower then Patient Low Level\n");
if ((ssaStatusOctet & SSA_RESULT_HIGHER_THAN_PATIENT_HIGH_LEVEL) > 0)
builder.append("- Result Higher then Patient High Level\n");
if ((ssaStatusOctet & SSA_RESULT_LOWER_THAN_HYPO_LEVEL) > 0)
builder.append("- Result Lower then Hypo Level\n");
if ((ssaStatusOctet & SSA_RESULT_HIGHER_THAN_HYPER_LEVEL) > 0)
builder.append("- Result Higher then Hyper Level\n");
if ((ssaStatusOctet & SSA_SENSOR_RATE_OF_DECREASE_EXCEEDED) > 0)
builder.append("- Sensor Rate of Decrease Exceeded\n");
if ((ssaStatusOctet & SSA_SENSOR_RATE_OF_INCREASE_EXCEEDED) > 0)
builder.append("- Sensor Rate of Increase Exceeded\n");
if ((ssaStatusOctet & SSA_RESULT_LOWER_THAN_DEVICE_CAN_PROCESS) > 0)
builder.append("- Result Lower then Device Can Process\n");
if ((ssaStatusOctet & SSA_RESULT_HIGHER_THAN_DEVICE_CAN_PROCESS) > 0)
builder.append("- Result Higher then Device Can Process\n");
}
if (cgmTrendInformationPresent) {
final float trend = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset);
offset += 2;
builder.append("Trend: ").append(trend).append(" mg/dL/min\n");
}
if (cgmQualityPresent) {
final float quality = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset);
offset += 2;
builder.append("Quality: ").append(quality).append("%\n");
}
if (size > offset + 1) {
final int crc = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
// offset += 2;
builder.append(String.format(Locale.US, "E2E-CRC: 0x%04X\n", crc));
}
builder.setLength(builder.length() - 1); // Remove last \n
return builder.toString();
}
}

View File

@@ -0,0 +1,294 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.nrftoolbox.parser;
import android.bluetooth.BluetoothGattCharacteristic;
public class CGMSpecificOpsControlPointParser {
private final static int OP_SET_CGM_COMMUNICATION_INTERVAL = 1;
private final static int OP_GET_CGM_COMMUNICATION_INTERVAL = 2;
private final static int OP_CGM_COMMUNICATION_INTERVAL_RESPONSE = 3;
private final static int OP_SET_GLUCOSE_CALIBRATION_VALUE = 4;
private final static int OP_GET_GLUCOSE_CALIBRATION_VALUE = 5;
private final static int OP_GLUCOSE_CALIBRATION_VALUE_RESPONSE = 6;
private final static int OP_SET_PATIENT_HIGH_ALERT_LEVEL = 7;
private final static int OP_GET_PATIENT_HIGH_ALERT_LEVEL = 8;
private final static int OP_PATIENT_HIGH_ALERT_LEVEL_RESPONSE = 9;
private final static int OP_SET_PATIENT_LOW_ALERT_LEVEL = 10;
private final static int OP_GET_PATIENT_LOW_ALERT_LEVEL = 11;
private final static int OP_PATIENT_LOW_ALERT_LEVEL_RESPONSE = 12;
private final static int OP_SET_HYPO_ALERT_LEVEL = 13;
private final static int OP_GET_HYPO_ALERT_LEVEL = 14;
private final static int OP_HYPO_ALERT_LEVEL_RESPONSE = 15;
private final static int OP_SET_HYPER_ALERT_LEVEL = 16;
private final static int OP_GET_HYPER_ALERT_LEVEL = 17;
private final static int OP_HYPER_ALERT_LEVEL_RESPONSE = 18;
private final static int OP_SET_RATE_OF_DECREASE_ALERT_LEVEL = 19;
private final static int OP_GET_RATE_OF_DECREASE_ALERT_LEVEL = 20;
private final static int OP_RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE = 21;
private final static int OP_SET_RATE_OF_INCREASE_ALERT_LEVEL = 22;
private final static int OP_GET_RATE_OF_INCREASE_ALERT_LEVEL = 23;
private final static int OP_RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE = 24;
private final static int OP_RESET_DEVICE_SPECIFIC_ALERT = 25;
private final static int OP_CODE_START_SESSION = 26;
private final static int OP_CODE_STOP_SESSION = 27;
private final static int OP_CODE_RESPONSE_CODE = 28;
// TODO this parser does not support E2E-CRC!
public static String parse(final BluetoothGattCharacteristic characteristic) {
int offset = 0;
final int opCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);
final StringBuilder builder = new StringBuilder();
builder.append(parseOpCode(opCode));
switch (opCode) {
case OP_SET_CGM_COMMUNICATION_INTERVAL:
case OP_CGM_COMMUNICATION_INTERVAL_RESPONSE: {
final int interval = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
builder.append(" to ").append(interval).append(" min");
break;
}
case OP_SET_GLUCOSE_CALIBRATION_VALUE: {
final float calConcentration = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset);
offset += 2;
final int calTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
offset += 2;
final int calTypeSampleLocation = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);
final int calType = calTypeSampleLocation & 0x0F;
final int calSampleLocation = (calTypeSampleLocation & 0xF0) >> 4;
// final int calNextCalibrationTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
// offset += 2;
// final int calCalibrationDataRecordNumber = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
// offset += 2;
// final int calStatus = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);
builder.append(" to:\n");
builder.append("Glucose Concentration of Calibration: ").append(calConcentration).append(" mg/dL\n");
builder.append("Time: ").append(calTime).append(" min\n");
builder.append("Type: ").append(parseType(calType)).append("\n");
builder.append("Sample Location: ").append(parseSampleLocation(calSampleLocation)).append("\n");
// builder.append("Next Calibration Time: ").append(parseNextCalibrationTime(calNextCalibrationTime)).append(" min\n"); // field ignored on Set
// builder.append("Data Record Number: ").append(calCalibrationDataRecordNumber).append("\n"); // field ignored on Set
// parseStatus(builder, calStatus); // field ignored on Set
break;
}
case OP_GET_GLUCOSE_CALIBRATION_VALUE: {
final int calibrationRecordNumber = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
builder.append(": ").append(parseRecordNumber(calibrationRecordNumber));
break;
}
case OP_GLUCOSE_CALIBRATION_VALUE_RESPONSE: {
final float calConcentration = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset);
offset += 2;
final int calTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
offset += 2;
final int calTypeSampleLocation = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);
final int calType = calTypeSampleLocation & 0x0F;
final int calSampleLocation = (calTypeSampleLocation & 0xF0) >> 4;
final int calNextCalibrationTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
offset += 2;
final int calCalibrationDataRecordNumber = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
offset += 2;
final int calStatus = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
builder.append(":\n");
if (calCalibrationDataRecordNumber > 0) {
builder.append("Glucose Concentration of Calibration: ").append(calConcentration).append(" mg/dL\n");
builder.append("Time: ").append(calTime).append(" min\n");
builder.append("Type: ").append(parseType(calType)).append("\n");
builder.append("Sample Location: ").append(parseSampleLocation(calSampleLocation)).append("\n");
builder.append("Next Calibration Time: ").append(parseNextCalibrationTime(calNextCalibrationTime)).append("\n");
builder.append("Data Record Number: ").append(calCalibrationDataRecordNumber);
parseStatus(builder, calStatus);
} else {
builder.append("No Calibration Data Stored");
}
break;
}
case OP_SET_PATIENT_HIGH_ALERT_LEVEL:
case OP_SET_PATIENT_LOW_ALERT_LEVEL:
case OP_SET_HYPO_ALERT_LEVEL:
case OP_SET_HYPER_ALERT_LEVEL: {
final float level = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset);
builder.append(" to: ").append(level).append(" mg/dL");
break;
}
case OP_PATIENT_HIGH_ALERT_LEVEL_RESPONSE:
case OP_PATIENT_LOW_ALERT_LEVEL_RESPONSE:
case OP_HYPO_ALERT_LEVEL_RESPONSE:
case OP_HYPER_ALERT_LEVEL_RESPONSE: {
final float level = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset);
builder.append(": ").append(level).append(" mg/dL");
break;
}
case OP_SET_RATE_OF_DECREASE_ALERT_LEVEL:
case OP_SET_RATE_OF_INCREASE_ALERT_LEVEL: {
final float level = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset);
builder.append(" to: ").append(level).append(" mg/dL/min");
break;
}
case OP_RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE:
case OP_RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE: {
final float level = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset);
builder.append(": ").append(level).append(" mg/dL/min");
break;
}
case OP_CODE_RESPONSE_CODE:
final int requestOpCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);
final int responseCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);
builder.append(" to ").append(parseOpCode(requestOpCode)).append(": ").append(parseResponseCode(responseCode));
break;
}
return builder.toString();
}
private static String parseOpCode(final int code) {
switch (code) {
case OP_SET_CGM_COMMUNICATION_INTERVAL:
return "Set CGM Communication Interval";
case OP_GET_CGM_COMMUNICATION_INTERVAL:
return "Get CGM Communication Interval";
case OP_CGM_COMMUNICATION_INTERVAL_RESPONSE:
return "CGM Communication Interval";
case OP_SET_GLUCOSE_CALIBRATION_VALUE:
return "Set CGM Calibration Value";
case OP_GET_GLUCOSE_CALIBRATION_VALUE:
return "Get CGM Calibration Value";
case OP_GLUCOSE_CALIBRATION_VALUE_RESPONSE:
return "CGM Calibration Value";
case OP_SET_PATIENT_HIGH_ALERT_LEVEL:
return "Set Patient High Alert Level";
case OP_GET_PATIENT_HIGH_ALERT_LEVEL:
return "Get Patient High Alert Level";
case OP_PATIENT_HIGH_ALERT_LEVEL_RESPONSE:
return "Patient High Alert Level";
case OP_SET_PATIENT_LOW_ALERT_LEVEL:
return "Set Patient Low Alert Level";
case OP_GET_PATIENT_LOW_ALERT_LEVEL:
return "Get Patient Low Alert Level";
case OP_PATIENT_LOW_ALERT_LEVEL_RESPONSE:
return "Patient Low Alert Level";
case OP_SET_HYPO_ALERT_LEVEL:
return "Set Hypo Alert Level";
case OP_GET_HYPO_ALERT_LEVEL:
return "Get Hypo Alert Level";
case OP_HYPO_ALERT_LEVEL_RESPONSE:
return "Hypo Alert Level";
case OP_SET_HYPER_ALERT_LEVEL:
return "Set Hyper Alert Level";
case OP_GET_HYPER_ALERT_LEVEL:
return "Get Hyper Alert Level";
case OP_HYPER_ALERT_LEVEL_RESPONSE:
return "Hyper Alert Level";
case OP_SET_RATE_OF_DECREASE_ALERT_LEVEL:
return "Set Rate of Decrease Alert Level";
case OP_GET_RATE_OF_DECREASE_ALERT_LEVEL:
return "Get Rate of Decrease Alert Level";
case OP_RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE:
return "Rate of Decrease Alert Level";
case OP_SET_RATE_OF_INCREASE_ALERT_LEVEL:
return "Set Rate of Increase Alert Level";
case OP_GET_RATE_OF_INCREASE_ALERT_LEVEL:
return "Get Rate of Increase Alert Level";
case OP_RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE:
return "Rate of Increase Alert Level";
case OP_RESET_DEVICE_SPECIFIC_ALERT:
return "Reset Device Specific Alert";
case OP_CODE_START_SESSION:
return "Start Session";
case OP_CODE_STOP_SESSION:
return "Stop Session";
case OP_CODE_RESPONSE_CODE:
return "Response";
default:
return "Reserved for future use (" + code + ")";
}
}
private static String parseResponseCode(final int code) {
switch (code) {
case 1: return "Success";
case 2: return "Op Code not supported";
case 3: return "Invalid Operand";
case 4: return "Procedure not completed";
case 5: return "Parameter out of range";
default:
return "Reserved for future use (" + code + ")";
}
}
private static String parseType(final int type) {
switch (type) {
case 1: return "Capillary Whole blood";
case 2: return "Capillary Plasma";
case 3: return "Capillary Whole blood";
case 4: return "Venous Plasma";
case 5: return "Arterial Whole blood";
case 6: return "Arterial Plasma";
case 7: return "Undetermined Whole blood";
case 8: return "Undetermined Plasma";
case 9: return "Interstitial Fluid (ISF)";
case 10: return "Control Solution";
default: return "Reserved for future use (" + type + ")";
}
}
private static String parseSampleLocation(final int location) {
switch (location) {
case 1: return "Finger";
case 2: return "Alternate Site Test (AST)";
case 3: return "Earlobe";
case 4: return "Control solution";
case 5: return "Subcutaneous tissue";
case 15: return "Sample Location value not available";
default: return "Reserved for future use (" + location + ")";
}
}
private static String parseNextCalibrationTime(final int time) {
if (time == 0)
return "Calibration Required Instantly";
return time + " min";
}
private static String parseRecordNumber(final int time) {
if (time == 0xFFFF)
return "Last Calibration Data";
return String.valueOf(time);
}
private static void parseStatus(final StringBuilder builder, final int status) {
if (status == 0)
return;
builder.append("\nStatus:\n");
if ((status & 1) > 0)
builder.append("- Calibration Data rejected");
if ((status & 2) > 0)
builder.append("- Calibration Data out of range");
if ((status & 4) > 0)
builder.append("- Calibration Process pending");
if ((status & 0xF8) > 0)
builder.append("- Reserved for future use (").append(status).append(")");
}
}

View File

@@ -33,11 +33,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.support.annotation.StringRes;
import java.util.Queue;
import java.util.UUID;
import no.nordicsemi.android.log.ILogSession;
import no.nordicsemi.android.log.LogContract;
import no.nordicsemi.android.log.Logger;
import no.nordicsemi.android.nrftoolbox.error.GattError;
import no.nordicsemi.android.nrftoolbox.utility.DebugLogger;
@@ -53,8 +55,8 @@ import no.nordicsemi.android.nrftoolbox.utility.ParserUtils;
* <li>The manager tries to read the Battery Level characteristic. No matter the result of this operation (for example the Battery Level characteristic may not have the READ property)
* it tries to enable Battery Level notifications, to get battery updates from the device.</li>
* <li>Afterwards, the manager initializes the device using given queue of commands. See {@link BleManagerGattCallback#initGatt(BluetoothGatt)} method for more details.</li>
* <li>When initialization complete, the {@link BleManagerCallbacks#onDeviceReady()} callback is called.</li>
* </ol>The manager also is responsible for parsing the Battery Level values and calling {@link BleManagerCallbacks#onBatteryValueReceived(int)} method.</p>
* <li>When initialization complete, the {@link BleManagerCallbacks#onDeviceReady(BluetoothDevice)} callback is called.</li>
* </ol>The manager also is responsible for parsing the Battery Level values and calling {@link BleManagerCallbacks#onBatteryValueReceived(BluetoothDevice, int)} method.</p>
* <p>Events from all profiles are being logged into the nRF Logger application,
* which may be downloaded from Google Play: <a href="https://play.google.com/store/apps/details?id=no.nordicsemi.android.log">https://play.google.com/store/apps/details?id=no.nordicsemi.android.log</a></p>
* <p>The nRF Logger application allows you to see application logs without need to connect it to the computer.</p>
@@ -82,11 +84,17 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
* The log session or null if nRF Logger is not installed.
*/
protected ILogSession mLogSession;
protected BluetoothDevice mBluetoothDevice;
protected E mCallbacks;
private Handler mHandler;
private BluetoothGatt mBluetoothGatt;
private Context mContext;
/**
* This flag is set to false only when the {@link #shouldAutoConnect()} method returns true and the device got disconnected without calling {@link #disconnect()} method.
* If {@link #shouldAutoConnect()} returns false (dafault) this is always set to true.
*/
private boolean mUserDisconnected;
/** Flag set to true when the device is connected. */
private boolean mConnected;
private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {
@@ -105,11 +113,11 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
switch (bondState) {
case BluetoothDevice.BOND_BONDING:
mCallbacks.onBondingRequired();
mCallbacks.onBondingRequired(device);
break;
case BluetoothDevice.BOND_BONDED:
Logger.i(mLogSession, "Device bonded");
mCallbacks.onBonded();
mCallbacks.onBonded(device);
// Start initializing again.
// In fact, bonding forces additional, internal service discovery (at least on Nexus devices), so this method may safely be used to start this process again.
@@ -199,6 +207,7 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
mUserDisconnected = !autoConnect; // We will receive Linkloss events only when the device is connected with autoConnect=true
Logger.v(mLogSession, "Connecting...");
Logger.d(mLogSession, "gatt = device.connectGatt(autoConnect = " + autoConnect + ")");
mBluetoothDevice = device;
mBluetoothGatt = device.connectGatt(mContext, autoConnect, getGattCallback());
}
@@ -211,7 +220,7 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
if (mConnected && mBluetoothGatt != null) {
Logger.v(mLogSession, "Disconnecting...");
mCallbacks.onDeviceDisconnecting();
mCallbacks.onDeviceDisconnecting(mBluetoothGatt.getDevice());
Logger.d(mLogSession, "gatt.disconnect()");
mBluetoothGatt.disconnect();
return true;
@@ -219,6 +228,13 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
return false;
}
/**
* This method returns true if the device is connected. Services could have not been discovered yet.
*/
public boolean isConnected() {
return mConnected;
}
/**
* Closes and releases resources. May be also used to unregister broadcast listeners.
*/
@@ -230,9 +246,11 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
// the receiver must have been not registered or unregistered before
}
if (mBluetoothGatt != null) {
Logger.d(mLogSession, "gatt.close()");
mBluetoothGatt.close();
mBluetoothGatt = null;
}
mBluetoothDevice = null;
mUserDisconnected = false;
}
@@ -248,6 +266,30 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
mLogSession = session;
}
/**
* Logs a message on the manager's log session. Does nothing when log session has not been set by {@link #setLogger(ILogSession)}.
* @param level
* the log level, one of {@link LogContract.Log.Level#DEBUG}, {@link LogContract.Log.Level#VERBOSE}, {@link LogContract.Log.Level#INFO}, {@link LogContract.Log.Level#WARNING},
* {@link LogContract.Log.Level#ERROR}
* @param message
* the message to be logged
*/
public void log(final int level, final String message) {
Logger.log(mLogSession, level, message);
}
/**
* Logs a message on the manager's log session. Does nothing when log session has not been set by {@link #setLogger(ILogSession)}.
* @param level
* the log level, one of {@link LogContract.Log.Level#DEBUG}, {@link LogContract.Log.Level#VERBOSE}, {@link LogContract.Log.Level#INFO}, {@link LogContract.Log.Level#WARNING},
* {@link LogContract.Log.Level#ERROR}
* @param messageRes
* the message string resource to be logged
*/
public void log(final int level, @StringRes final int messageRes) {
Logger.log(mLogSession, level, messageRes);
}
/**
* Sets the manager callback listener
*
@@ -573,7 +615,7 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
* Called then the initialization queue is complete.
*/
protected void onDeviceReady() {
mCallbacks.onDeviceReady();
mCallbacks.onDeviceReady(mBluetoothGatt.getDevice());
}
/**
@@ -617,9 +659,9 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
// do nothing
}
private void onError(final String message, final int errorCode) {
private void onError(final BluetoothDevice device, final String message, final int errorCode) {
Logger.e(mLogSession, "Error (0x" + Integer.toHexString(errorCode) + "): " + GattError.parse(errorCode));
mCallbacks.onError(message, errorCode);
mCallbacks.onError(device, message, errorCode);
}
@Override
@@ -630,7 +672,7 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
// Notify the parent activity/service
Logger.i(mLogSession, "Connected to " + gatt.getDevice().getAddress());
mConnected = true;
mCallbacks.onDeviceConnected();
mCallbacks.onDeviceConnected(gatt.getDevice());
/*
* The onConnectionStateChange event is triggered just after the Android connects to a device.
@@ -668,11 +710,11 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
mConnected = false;
if (mUserDisconnected) {
Logger.i(mLogSession, "Disconnected");
mCallbacks.onDeviceDisconnected();
mCallbacks.onDeviceDisconnected(gatt.getDevice());
close();
} else {
Logger.w(mLogSession, "Connection lost");
mCallbacks.onLinklossOccur();
mCallbacks.onLinklossOccur(gatt.getDevice());
// We are not closing the connection here as the device should try to reconnect automatically.
// This may be only called when the shouldAutoConnect() method returned true.
}
@@ -681,7 +723,7 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
// TODO Should the disconnect method be called or the connection is still valid? Does this ever happen?
Logger.e(mLogSession, "Error (0x" + Integer.toHexString(status) + "): " + GattError.parseConnectionError(status));
mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status);
mCallbacks.onError(gatt.getDevice(), ERROR_CONNECTION_STATE_CHANGE, status);
}
}
@@ -696,7 +738,7 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
Logger.v(mLogSession, "Secondary service found");
// Notify the parent activity
mCallbacks.onServicesDiscovered(optionalServicesFound);
mCallbacks.onServicesDiscovered(gatt.getDevice(), optionalServicesFound);
// Obtain the queue of initialization requests
mInitInProgress = true;
@@ -713,12 +755,12 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
nextRequest();
} else {
Logger.w(mLogSession, "Device is not supported");
mCallbacks.onDeviceNotSupported();
mCallbacks.onDeviceNotSupported(gatt.getDevice());
disconnect();
}
} else {
DebugLogger.e(TAG, "onServicesDiscovered error " + status);
onError(ERROR_DISCOVERY_SERVICE, status);
onError(gatt.getDevice(), ERROR_DISCOVERY_SERVICE, status);
}
}
@@ -730,7 +772,7 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
if (isBatteryLevelCharacteristic(characteristic)) {
final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
Logger.a(mLogSession, "Battery level received: " + batteryValue + "%");
mCallbacks.onBatteryValueReceived(batteryValue);
mCallbacks.onBatteryValueReceived(gatt.getDevice(), batteryValue);
// The Battery Level value has been read. Let's try to enable Battery Level notifications.
// If the Battery Level characteristic does not have the NOTIFY property, proceed with the initialization queue.
@@ -744,16 +786,16 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED);
mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status);
mCallbacks.onError(gatt.getDevice(), ERROR_AUTH_ERROR_WHILE_BONDED, status);
}
} else {
DebugLogger.e(TAG, "onCharacteristicRead error " + status);
onError(ERROR_READ_CHARACTERISTIC, status);
onError(gatt.getDevice(), ERROR_READ_CHARACTERISTIC, status);
}
}
@Override
public void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
public final void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Logger.i(mLogSession, "Data written to " + characteristic.getUuid() + ", value: " + ParserUtils.parse(characteristic.getValue()));
// The value has been written. Notify the manager and proceed with the initialization queue.
@@ -762,11 +804,11 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED);
mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status);
mCallbacks.onError(gatt.getDevice(), ERROR_AUTH_ERROR_WHILE_BONDED, status);
}
} else {
DebugLogger.e(TAG, "onCharacteristicRead error " + status);
onError(ERROR_READ_CHARACTERISTIC, status);
onError(gatt.getDevice(), ERROR_READ_CHARACTERISTIC, status);
}
}
@@ -792,11 +834,11 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED);
mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status);
mCallbacks.onError(gatt.getDevice(), ERROR_AUTH_ERROR_WHILE_BONDED, status);
}
} else {
DebugLogger.e(TAG, "onDescriptorWrite error " + status);
onError(ERROR_WRITE_DESCRIPTOR, status);
onError(gatt.getDevice(), ERROR_WRITE_DESCRIPTOR, status);
}
}
@@ -808,7 +850,7 @@ public abstract class BleManager<E extends BleManagerCallbacks> {
Logger.i(mLogSession, "Notification received from " + characteristic.getUuid() + ", value: " + data);
final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
Logger.a(mLogSession, "Battery level received: " + batteryValue + "%");
mCallbacks.onBatteryValueReceived(batteryValue);
mCallbacks.onBatteryValueReceived(gatt.getDevice(), batteryValue);
} else {
final BluetoothGattDescriptor cccd = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
final boolean notifications = cccd == null || cccd.getValue() == null || cccd.getValue().length != 2 || cccd.getValue()[0] == 0x01;

View File

@@ -21,6 +21,7 @@
*/
package no.nordicsemi.android.nrftoolbox.profile;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
@@ -28,71 +29,82 @@ public interface BleManagerCallbacks {
/**
* Called when the device has been connected. This does not mean that the application may start communication. A service discovery will be handled automatically after this call. Service discovery
* may ends up with calling {@link #onServicesDiscovered(boolean)} or {@link #onDeviceNotSupported()} if required services have not been found.
* may ends up with calling {@link #onServicesDiscovered(BluetoothDevice, boolean)} or {@link #onDeviceNotSupported(BluetoothDevice)} if required services have not been found.
* @param device the device that got connected
*/
public void onDeviceConnected();
void onDeviceConnected(final BluetoothDevice device);
/**
* Called when user initialized disconnection.
* @param device the device that gets disconnecting
*/
public void onDeviceDisconnecting();
void onDeviceDisconnecting(final BluetoothDevice device);
/**
* Called when the device has disconnected (when the callback returned {@link BluetoothGattCallback#onConnectionStateChange(BluetoothGatt, int, int)} with state DISCONNECTED.
* @param device the device that got disconnected
*/
public void onDeviceDisconnected();
void onDeviceDisconnected(final BluetoothDevice device);
/**
* This callback is invoked when the Ble Manager lost connection to a device that has been connected with autoConnect option. Otherwise a {@link #onDeviceDisconnected()}
* This callback is invoked when the Ble Manager lost connection to a device that has been connected with autoConnect option. Otherwise a {@link #onDeviceDisconnected(BluetoothDevice)}
* method will be called on such event.
* @param device the device that got disconnected due to a link loss
*/
public void onLinklossOccur();
void onLinklossOccur(final BluetoothDevice device);
/**
* Called when service discovery has finished and primary services has been found. The device is ready to operate. This method is not called if the primary, mandatory services were not found
* during service discovery. For example in the Blood Pressure Monitor, a Blood Pressure service is a primary service and Intermediate Cuff Pressure service is a optional secondary service.
* Existence of battery service is not notified by this call.
*
*
* @param optionalServicesFound
* if <code>true</code> the secondary services were also found on the device.
* @param device the device which services got disconnected
*/
public void onServicesDiscovered(final boolean optionalServicesFound);
void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound);
/**
* Method called when all initialization requests has been completed.
* @param device the device that get ready
*/
public void onDeviceReady();
void onDeviceReady(final BluetoothDevice device);
/**
* Called when battery value has been received from the device.
*
*
* @param value
* the battery value in percent
* @param device the device frm which the battery value has changed
*/
public void onBatteryValueReceived(final int value);
void onBatteryValueReceived(final BluetoothDevice device, final int value);
/**
* Called when an {@link BluetoothGatt#GATT_INSUFFICIENT_AUTHENTICATION} error occurred and the device bond state is NOT_BONDED
* @param device the device that requires bonding
*/
public void onBondingRequired();
void onBondingRequired(final BluetoothDevice device);
/**
* Called when the device has been successfully bonded.
* @param device the device that got bonded
*/
public void onBonded();
void onBonded(final BluetoothDevice device);
/**
* Called when a BLE error has occurred
*
*
* @param message
* the error message
* @param errorCode
* the error code
* @param device the device that caused an error
*/
public void onError(final String message, final int errorCode);
void onError(final BluetoothDevice device, final String message, final int errorCode);
/**
* Called when service discovery has finished but the main services were not found on the device.
* @param device the device that failed to connect due to lack of required services
*/
public void onDeviceNotSupported();
void onDeviceNotSupported(final BluetoothDevice device);
}

View File

@@ -239,7 +239,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
}
@Override
public void onDeviceConnected() {
public void onDeviceConnected(final BluetoothDevice device) {
mDeviceConnected = true;
runOnUiThread(new Runnable() {
@Override
@@ -251,12 +251,12 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
}
@Override
public void onDeviceDisconnecting() {
public void onDeviceDisconnecting(final BluetoothDevice device) {
// do nothing
}
@Override
public void onDeviceDisconnected() {
public void onDeviceDisconnected(final BluetoothDevice device) {
mDeviceConnected = false;
mBleManager.close();
runOnUiThread(new Runnable() {
@@ -271,7 +271,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
}
@Override
public void onLinklossOccur() {
public void onLinklossOccur(final BluetoothDevice device) {
mDeviceConnected = false;
runOnUiThread(new Runnable() {
@Override
@@ -284,7 +284,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
}
@Override
public void onBatteryValueReceived(final int value) {
public void onBatteryValueReceived(final BluetoothDevice device, final int value) {
runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -294,23 +294,23 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
}
@Override
public void onBondingRequired() {
public void onBondingRequired(final BluetoothDevice device) {
showToast(R.string.bonding);
}
@Override
public void onBonded() {
public void onBonded(final BluetoothDevice device) {
showToast(R.string.bonded);
}
@Override
public void onError(final String message, final int errorCode) {
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
DebugLogger.e(TAG, "Error occurred: " + message + ", error code: " + errorCode);
showToast(message + " (" + errorCode + ")");
}
@Override
public void onDeviceNotSupported() {
public void onDeviceNotSupported(final BluetoothDevice device) {
showToast(R.string.not_supported);
}

View File

@@ -51,8 +51,8 @@ import no.nordicsemi.android.nrftoolbox.utility.DebugLogger;
public abstract class BleProfileExpandableListActivity extends ExpandableListActivity implements BleManagerCallbacks, ScannerFragment.OnDeviceSelectedListener {
private static final String TAG = "BaseProfileActivity";
private static final String CONNECTION_STATUS = "connection_status";
private static final String DEVICE_NAME = "device_name";
private static final String SIS_CONNECTION_STATUS = "connection_status";
private static final String SIS_DEVICE_NAME = "device_name";
protected static final int REQUEST_ENABLE_BT = 2;
private BleManager<? extends BleManagerCallbacks> mBleManager;
@@ -127,15 +127,15 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
@Override
protected void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(CONNECTION_STATUS, mDeviceConnected);
outState.putString(DEVICE_NAME, mDeviceName);
outState.putBoolean(SIS_CONNECTION_STATUS, mDeviceConnected);
outState.putString(SIS_DEVICE_NAME, mDeviceName);
}
@Override
protected void onRestoreInstanceState(final Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mDeviceConnected = savedInstanceState.getBoolean(CONNECTION_STATUS);
mDeviceName = savedInstanceState.getString(DEVICE_NAME);
mDeviceConnected = savedInstanceState.getBoolean(SIS_CONNECTION_STATUS);
mDeviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
if (mDeviceConnected) {
mConnectButton.setText(R.string.action_disconnect);
@@ -236,7 +236,7 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
}
@Override
public void onDeviceConnected() {
public void onDeviceConnected(final BluetoothDevice device) {
mDeviceConnected = true;
runOnUiThread(new Runnable() {
@Override
@@ -248,12 +248,12 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
}
@Override
public void onDeviceDisconnecting() {
public void onDeviceDisconnecting(final BluetoothDevice device) {
// do nothing
}
@Override
public void onDeviceDisconnected() {
public void onDeviceDisconnected(final BluetoothDevice device) {
mDeviceConnected = false;
mBleManager.close();
runOnUiThread(new Runnable() {
@@ -267,7 +267,7 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
}
@Override
public void onLinklossOccur() {
public void onLinklossOccur(final BluetoothDevice device) {
mDeviceConnected = false;
runOnUiThread(new Runnable() {
@Override
@@ -280,19 +280,19 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
}
@Override
public void onServicesDiscovered(boolean optionalServicesFound) {
public void onServicesDiscovered(final BluetoothDevice device, boolean optionalServicesFound) {
// this may notify user or show some views
}
/**
* Called when the initialization process in completed.
*/
public void onDeviceReady() {
public void onDeviceReady(final BluetoothDevice device) {
// empty default implementation
}
@Override
public void onBatteryValueReceived(final int value) {
public void onBatteryValueReceived(final BluetoothDevice device, final int value) {
runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -302,23 +302,23 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
}
@Override
public void onBondingRequired() {
public void onBondingRequired(final BluetoothDevice device) {
showToast(R.string.bonding);
}
@Override
public void onBonded() {
public void onBonded(final BluetoothDevice device) {
showToast(R.string.bonded);
}
@Override
public void onError(final String message, final int errorCode) {
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
DebugLogger.e(TAG, "Error occurred: " + message + ", error code: " + errorCode);
showToast(message + " (" + errorCode + ")");
}
@Override
public void onDeviceNotSupported() {
public void onDeviceNotSupported(final BluetoothDevice device) {
showToast(R.string.not_supported);
}

View File

@@ -51,6 +51,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
public static final String EXTRA_DEVICE_ADDRESS = "no.nordicsemi.android.nrftoolbox.EXTRA_DEVICE_ADDRESS";
/** The key for the device name that is returned in {@link #BROADCAST_CONNECTION_STATE} with state {@link #STATE_CONNECTED}. */
public static final String EXTRA_DEVICE_NAME = "no.nordicsemi.android.nrftoolbox.EXTRA_DEVICE_NAME";
public static final String EXTRA_DEVICE = "no.nordicsemi.android.nrftoolbox.EXTRA_DEVICE";
public static final String EXTRA_LOG_URI = "no.nordicsemi.android.nrftoolbox.EXTRA_LOG_URI";
public static final String EXTRA_CONNECTION_STATE = "no.nordicsemi.android.nrftoolbox.EXTRA_CONNECTION_STATE";
public static final String EXTRA_BOND_STATE = "no.nordicsemi.android.nrftoolbox.EXTRA_BOND_STATE";
@@ -72,7 +73,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
protected boolean mBinded;
private boolean mActivityFinished;
private boolean mConnected;
private String mDeviceAddress;
private BluetoothDevice mBluetoothDevice;
private String mDeviceName;
private ILogSession mLogSession;
@@ -83,7 +84,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
public final void disconnect() {
if (!mConnected) {
mBleManager.close();
onDeviceDisconnected();
onDeviceDisconnected(mBluetoothDevice);
return;
}
@@ -104,7 +105,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return device address
*/
public String getDeviceAddress() {
return mDeviceAddress;
return mBluetoothDevice.getAddress();
}
/**
@@ -116,6 +117,15 @@ public abstract class BleProfileService extends Service implements BleManagerCal
return mDeviceName;
}
/**
* Returns the Bluetooth device
*
* @return the Bluetooth device
*/
public BluetoothDevice getBluetoothDevice() {
return mBluetoothDevice;
}
/**
* Returns <code>true</code> if the device is connected to the sensor.
*
@@ -218,7 +228,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal
final Uri logUri = intent.getParcelableExtra(EXTRA_LOG_URI);
mLogSession = Logger.openSession(getApplicationContext(), logUri);
mDeviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
mDeviceName = intent.getStringExtra(EXTRA_DEVICE_NAME);
Logger.i(mLogSession, "Service started");
@@ -229,11 +239,11 @@ public abstract class BleProfileService extends Service implements BleManagerCal
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
final BluetoothAdapter adapter = bluetoothManager.getAdapter();
final BluetoothDevice device = adapter.getRemoteDevice(mDeviceAddress);
mDeviceName = device.getName();
final String deviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
mBluetoothDevice = adapter.getRemoteDevice(deviceAddress);
onServiceStarted();
mBleManager.connect(device);
mBleManager.connect(mBluetoothDevice);
return START_REDELIVER_INTENT;
}
@@ -252,27 +262,28 @@ public abstract class BleProfileService extends Service implements BleManagerCal
mBleManager.close();
Logger.i(mLogSession, "Service destroyed");
mBleManager = null;
mDeviceAddress = null;
mBluetoothDevice = null;
mDeviceName = null;
mConnected = false;
mLogSession = null;
}
@Override
public void onDeviceConnected() {
public void onDeviceConnected(final BluetoothDevice device) {
mConnected = true;
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED);
broadcast.putExtra(EXTRA_DEVICE_ADDRESS, mDeviceAddress);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_DEVICE_NAME, mDeviceName);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onDeviceDisconnecting() {
public void onDeviceDisconnecting(final BluetoothDevice device) {
// Notify user about changing the state to DISCONNECTING
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@@ -287,12 +298,12 @@ public abstract class BleProfileService extends Service implements BleManagerCal
}
@Override
public void onDeviceDisconnected() {
public void onDeviceDisconnected(final BluetoothDevice device) {
mConnected = false;
mDeviceAddress = null;
mDeviceName = null;
// Do not use the device argument here unless you change calling onDeviceDisconnected from the binder above
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
@@ -307,31 +318,35 @@ public abstract class BleProfileService extends Service implements BleManagerCal
}
@Override
public void onLinklossOccur() {
public void onLinklossOccur(final BluetoothDevice device) {
mConnected = false;
final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onServicesDiscovered(final boolean optionalServicesFound) {
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_SERVICE_PRIMARY, true);
broadcast.putExtra(EXTRA_SERVICE_SECONDARY, optionalServicesFound);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onDeviceReady() {
public void onDeviceReady(final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_DEVICE_READY);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onDeviceNotSupported() {
public void onDeviceNotSupported(final BluetoothDevice device) {
final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_SERVICE_PRIMARY, false);
broadcast.putExtra(EXTRA_SERVICE_SECONDARY, false);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
@@ -340,33 +355,37 @@ public abstract class BleProfileService extends Service implements BleManagerCal
}
@Override
public void onBatteryValueReceived(final int value) {
public void onBatteryValueReceived(final BluetoothDevice device, final int value) {
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_BATTERY_LEVEL, value);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onBondingRequired() {
public void onBondingRequired(final BluetoothDevice device) {
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding);
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onBonded() {
public void onBonded(final BluetoothDevice device) {
showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonded);
final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}
@Override
public void onError(final String message, final int errorCode) {
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
final Intent broadcast = new Intent(BROADCAST_ERROR);
broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice);
broadcast.putExtra(EXTRA_ERROR_MESSAGE, message);
broadcast.putExtra(EXTRA_ERROR_CODE, errorCode);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
@@ -421,7 +440,16 @@ public abstract class BleProfileService extends Service implements BleManagerCal
* @return device address
*/
protected String getDeviceAddress() {
return mDeviceAddress;
return mBluetoothDevice.getAddress();
}
/**
* Returns the Bluetooth device object
*
* @return bluetooth device
*/
protected BluetoothDevice getBluetoothDevice() {
return mBluetoothDevice;
}
/**

View File

@@ -24,7 +24,6 @@ package no.nordicsemi.android.nrftoolbox.profile;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -73,7 +72,8 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
ScannerFragment.OnDeviceSelectedListener, BleManagerCallbacks {
private static final String TAG = "BleProfileServiceReadyActivity";
private static final String DEVICE_NAME = "device_name";
private static final String SIS_DEVICE_NAME = "device_name";
private static final String SIS_DEVICE = "device";
private static final String LOG_URI = "log_uri";
protected static final int REQUEST_ENABLE_BT = 2;
@@ -84,13 +84,18 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
private Button mConnectButton;
private ILogSession mLogSession;
private BluetoothDevice mBluetoothDevice;
private String mDeviceName;
private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
// Check if the broadcast applies the connected device
if (!isBroadcastForThisDevice(intent))
return;
final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleProfileService.EXTRA_DEVICE);
final String action = intent.getAction();
switch (action) {
case BleProfileService.BROADCAST_CONNECTION_STATE: {
final int state = intent.getIntExtra(BleProfileService.EXTRA_CONNECTION_STATE, BleProfileService.STATE_DISCONNECTED);
@@ -98,16 +103,16 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
switch (state) {
case BleProfileService.STATE_CONNECTED: {
mDeviceName = intent.getStringExtra(BleProfileService.EXTRA_DEVICE_NAME);
onDeviceConnected();
onDeviceConnected(bluetoothDevice);
break;
}
case BleProfileService.STATE_DISCONNECTED: {
onDeviceDisconnected();
onDeviceDisconnected(bluetoothDevice);
mDeviceName = null;
break;
}
case BleProfileService.STATE_LINK_LOSS: {
onLinklossOccur();
onLinklossOccur(bluetoothDevice);
break;
}
case BleProfileService.STATE_CONNECTING:
@@ -124,24 +129,24 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
final boolean secondaryService = intent.getBooleanExtra(BleProfileService.EXTRA_SERVICE_SECONDARY, false);
if (primaryService) {
onServicesDiscovered(secondaryService);
onServicesDiscovered(bluetoothDevice, secondaryService);
} else {
onDeviceNotSupported();
onDeviceNotSupported(bluetoothDevice);
}
break;
}
case BleProfileService.BROADCAST_DEVICE_READY: {
onDeviceReady();
onDeviceReady(bluetoothDevice);
break;
}
case BleProfileService.BROADCAST_BOND_STATE: {
final int state = intent.getIntExtra(BleProfileService.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
switch (state) {
case BluetoothDevice.BOND_BONDING:
onBondingRequired();
onBondingRequired(bluetoothDevice);
break;
case BluetoothDevice.BOND_BONDED:
onBonded();
onBonded(bluetoothDevice);
break;
}
break;
@@ -149,13 +154,13 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
case BleProfileService.BROADCAST_BATTERY_LEVEL: {
final int value = intent.getIntExtra(BleProfileService.EXTRA_BATTERY_LEVEL, -1);
if (value > 0)
onBatteryValueReceived(value);
onBatteryValueReceived(bluetoothDevice, value);
break;
}
case BleProfileService.BROADCAST_ERROR: {
final String message = intent.getStringExtra(BleProfileService.EXTRA_ERROR_MESSAGE);
final int errorCode = intent.getIntExtra(BleProfileService.EXTRA_ERROR_CODE, 0);
onError(message, errorCode);
onError(bluetoothDevice, message, errorCode);
break;
}
}
@@ -167,6 +172,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
@Override
public void onServiceConnected(final ComponentName name, final IBinder service) {
final E bleService = mService = (E) service;
mBluetoothDevice = bleService.getBluetoothDevice();
mLogSession = mService.getLogSession();
Logger.d(mLogSession, "Activity binded to the service");
onServiceBinded(bleService);
@@ -178,7 +184,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
// and notify user if device is connected
if (bleService.isConnected())
onDeviceConnected();
onDeviceConnected(mBluetoothDevice);
}
@Override
@@ -189,6 +195,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
mService = null;
mDeviceName = null;
mBluetoothDevice = null;
mLogSession = null;
onServiceUnbinded();
}
@@ -260,6 +267,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
Logger.d(mLogSession, "Activity unbinded from the service");
onServiceUnbinded();
mDeviceName = null;
mBluetoothDevice = null;
mLogSession = null;
} catch (final IllegalArgumentException e) {
// do nothing, we were not connected to the sensor
@@ -351,7 +359,8 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
@Override
protected void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(DEVICE_NAME, mDeviceName);
outState.putString(SIS_DEVICE_NAME, mDeviceName);
outState.putParcelable(SIS_DEVICE, mBluetoothDevice);
if (mLogSession != null)
outState.putParcelable(LOG_URI, mLogSession.getSessionUri());
}
@@ -359,7 +368,8 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
@Override
protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mDeviceName = savedInstanceState.getString(DEVICE_NAME);
mDeviceName = savedInstanceState.getString(SIS_DEVICE_NAME);
mBluetoothDevice = savedInstanceState.getParcelable(SIS_DEVICE);
}
@Override
@@ -441,6 +451,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name);
}
}
mBluetoothDevice = device;
mDeviceName = name;
mDeviceNameView.setText(name != null ? name : getString(R.string.not_available));
mConnectButton.setText(R.string.action_connecting);
@@ -450,6 +461,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
Logger.d(mLogSession, "Creating service...");
final Intent service = new Intent(this, getServiceClass());
service.putExtra(BleProfileService.EXTRA_DEVICE_ADDRESS, device.getAddress());
service.putExtra(BleProfileService.EXTRA_DEVICE_NAME, name);
if (mLogSession != null)
service.putExtra(BleProfileService.EXTRA_LOG_URI, mLogSession.getSessionUri());
startService(service);
@@ -462,27 +474,20 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
// do nothing
}
/**
* Called when the device has been connected. This does not mean that the application may start communication. A service discovery will be handled
* automatically after this call. Service discovery may ends up with calling {@link #onServicesDiscovered(boolean)} or {@link #onDeviceNotSupported()} if required
* services have not been found.
*/
public void onDeviceConnected() {
@Override
public void onDeviceConnected(final BluetoothDevice device) {
mDeviceNameView.setText(mDeviceName);
mConnectButton.setText(R.string.action_disconnect);
mConnectButton.setEnabled(true);
}
@Override
public void onDeviceDisconnecting() {
// do nothing
public void onDeviceDisconnecting(final BluetoothDevice device) {
// do nothing
}
/**
* Called when the device has disconnected (when the callback returned
* {@link BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} with state DISCONNECTED.
*/
public void onDeviceDisconnected() {
@Override
public void onDeviceDisconnected(final BluetoothDevice device) {
mConnectButton.setText(R.string.action_connect);
mDeviceNameView.setText(getDefaultDeviceName());
if (mBatteryLevelView != null)
@@ -493,79 +498,53 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
unbindService(mServiceConnection);
mService = null;
Logger.d(mLogSession, "Activity unbinded from the service");
Logger.d(mLogSession, "Activity unbound from the service");
onServiceUnbinded();
mDeviceName = null;
mBluetoothDevice = null;
mLogSession = null;
} catch (final IllegalArgumentException e) {
// do nothing. This should never happen but does...
}
}
/**
* Some profiles may use this method to notify user that the link was lost. You must call this method in your Ble Manager instead of
* {@link #onDeviceDisconnected()} while you discover disconnection not initiated by the user.
*/
public void onLinklossOccur() {
@Override
public void onLinklossOccur(final BluetoothDevice device) {
if (mBatteryLevelView != null)
mBatteryLevelView.setText(R.string.not_available);
}
/**
* Called when service discovery has finished and primary services has been found. The device is ready to operate. This method is not called if the primary,
* mandatory services were not found during service discovery. For example in the Blood Pressure Monitor, a Blood Pressure service is a primary service and
* Intermediate Cuff Pressure service is a optional secondary service. Existence of battery service is not notified by this call.
*
* @param optionalServicesFound if <code>true</code> the secondary services were also found on the device.
*/
public abstract void onServicesDiscovered(final boolean optionalServicesFound);
@Override
public abstract void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound);
/**
* Called when the initialization process in completed.
*/
public void onDeviceReady() {
@Override
public void onDeviceReady(final BluetoothDevice device) {
// empty default implementation
}
/**
* Called when the device has started bonding process
*/
public void onBondingRequired() {
@Override
public void onBondingRequired(final BluetoothDevice device) {
// empty default implementation
}
/**
* Called when the device has finished bonding process successfully
*/
public void onBonded() {
@Override
public void onBonded(final BluetoothDevice device) {
// empty default implementation
}
/**
* Called when service discovery has finished but the main services were not found on the device. This may occur when connecting to bonded device that does
* not support required services.
*/
public void onDeviceNotSupported() {
@Override
public void onDeviceNotSupported(final BluetoothDevice device) {
showToast(R.string.not_supported);
}
/**
* Called when battery value has been received from the device
*
* @param value the battery value in percent
*/
public void onBatteryValueReceived(final int value) {
@Override
public void onBatteryValueReceived(final BluetoothDevice device, final int value) {
if (mBatteryLevelView != null)
mBatteryLevelView.setText(getString(R.string.battery, value));
}
/**
* Called when a BLE error has occurred
*
* @param message the error message
* @param errorCode the error code
*/
public void onError(final String message, final int errorCode) {
@Override
public void onError(final BluetoothDevice device, final String message, final int errorCode) {
DebugLogger.e(TAG, "Error occurred: " + message + ", error code: " + errorCode);
showToast(message + " (" + errorCode + ")");
}
@@ -640,6 +619,16 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
*/
protected abstract UUID getFilterUUID();
/**
* Checks the {@link BleProfileService#EXTRA_DEVICE} in the given intent and compares it with the connected BluetoothDevice object.
* @param intent intent received via a broadcast from the service
* @return true if the data in the intent apply to the connected device, false otherwise
*/
protected boolean isBroadcastForThisDevice(final Intent intent) {
final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleProfileService.EXTRA_DEVICE);
return mBluetoothDevice != null && mBluetoothDevice.equals(bluetoothDevice);
}
/**
* Shows the scanner fragment.
*

View File

@@ -21,6 +21,7 @@
*/
package no.nordicsemi.android.nrftoolbox.proximity;
import android.bluetooth.BluetoothDevice;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
@@ -134,35 +135,35 @@ public class ProximityActivity extends BleProfileServiceReadyActivity<ProximityS
}
@Override
public void onServicesDiscovered(boolean optionalServicesFound) {
public void onServicesDiscovered(final BluetoothDevice device, boolean optionalServicesFound) {
// this may notify user or update views
}
@Override
public void onDeviceReady() {
public void onDeviceReady(final BluetoothDevice device) {
showOpenLock();
}
@Override
public void onDeviceDisconnected() {
super.onDeviceDisconnected();
public void onDeviceDisconnected(final BluetoothDevice device) {
super.onDeviceDisconnected(device);
showClosedLock();
mGattServerSwitch.setEnabled(true);
}
@Override
public void onBondingRequired() {
public void onBondingRequired(final BluetoothDevice device) {
showClosedLock();
}
@Override
public void onBonded() {
public void onBonded(final BluetoothDevice device) {
showOpenLock();
}
@Override
public void onLinklossOccur() {
super.onLinklossOccur();
public void onLinklossOccur(final BluetoothDevice device) {
super.onLinklossOccur(device);
showClosedLock();
resetForLinkloss();

View File

@@ -185,10 +185,10 @@ public class ProximityManager extends BleManager<ProximityManagerCallbacks> {
if (!preparedWrite && value != null && value.length == 1) { // small validation
if (value[0] != NO_ALERT[0]) {
Logger.a(mLogSession, "[Server] Immediate alarm request received: " + AlertLevelParser.parse(characteristic));
mCallbacks.onAlarmTriggered();
mCallbacks.onAlarmTriggered(device);
} else {
Logger.a(mLogSession, "[Server] Immediate alarm request received: OFF");
mCallbacks.onAlarmStopped();
mCallbacks.onAlarmStopped(device);
}
}
@@ -279,7 +279,7 @@ public class ProximityManager extends BleManager<ProximityManagerCallbacks> {
@Override
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
requests.push(Request.newWriteRequest(mLinklossCharacteristic, HIGH_ALERT));
requests.add(Request.newWriteRequest(mLinklossCharacteristic, HIGH_ALERT));
return requests;
}
@@ -306,10 +306,14 @@ public class ProximityManager extends BleManager<ProximityManagerCallbacks> {
mAlertLevelCharacteristic = null;
mLinklossCharacteristic = null;
}
@Override
protected void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
Logger.a(mLogSession, "\"" + AlertLevelParser.parse(characteristic) + "\" sent");
}
};
public void writeImmediateAlertOn() {
Logger.a(mLogSession, "Immediate alarm request: ON");
if (mAlertLevelCharacteristic != null) {
mAlertLevelCharacteristic.setValue(HIGH_ALERT);
writeCharacteristic(mAlertLevelCharacteristic);
@@ -319,7 +323,6 @@ public class ProximityManager extends BleManager<ProximityManagerCallbacks> {
}
public void writeImmediateAlertOff() {
Logger.a(mLogSession, "Immediate alarm request: OFF");
if (mAlertLevelCharacteristic != null) {
mAlertLevelCharacteristic.setValue(NO_ALERT);
writeCharacteristic(mAlertLevelCharacteristic);

View File

@@ -21,10 +21,12 @@
*/
package no.nordicsemi.android.nrftoolbox.proximity;
import android.bluetooth.BluetoothDevice;
import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
public interface ProximityManagerCallbacks extends BleManagerCallbacks {
public void onAlarmTriggered();
void onAlarmTriggered(final BluetoothDevice device);
public void onAlarmStopped();
void onAlarmStopped(final BluetoothDevice device);
}

View File

@@ -24,6 +24,7 @@ package no.nordicsemi.android.nrftoolbox.proximity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -169,19 +170,19 @@ public class ProximityService extends BleProfileService implements ProximityMana
}
@Override
public void onDeviceDisconnecting() {
public void onDeviceDisconnecting(final BluetoothDevice device) {
stopAlarm();
}
@Override
public void onDeviceDisconnected() {
super.onDeviceDisconnected();
public void onDeviceDisconnected(final BluetoothDevice device) {
super.onDeviceDisconnected(device);
isImmediateAlertOn = false;
}
@Override
public void onLinklossOccur() {
super.onLinklossOccur();
public void onLinklossOccur(final BluetoothDevice device) {
super.onLinklossOccur(device);
isImmediateAlertOn = false;
if (!mBinded) {
@@ -192,12 +193,12 @@ public class ProximityService extends BleProfileService implements ProximityMana
}
@Override
public void onAlarmTriggered() {
public void onAlarmTriggered(final BluetoothDevice device) {
playAlarm();
}
@Override
public void onAlarmStopped() {
public void onAlarmStopped(final BluetoothDevice device) {
stopAlarm();
}

View File

@@ -22,6 +22,7 @@
package no.nordicsemi.android.nrftoolbox.rsc;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -33,6 +34,7 @@ import android.support.v4.content.LocalBroadcastManager;
import android.view.Menu;
import android.widget.TextView;
import java.util.Locale;
import java.util.UUID;
import no.nordicsemi.android.nrftoolbox.R;
@@ -175,7 +177,7 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
}
@Override
public void onServicesDiscovered(final boolean optionalServicesFound) {
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
// not used
}
@@ -192,7 +194,7 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
mTotalDistanceView.setText(R.string.not_available);
mTotalDistanceUnitView.setText(null);
} else {
mTotalDistanceView.setText(String.format("%.2f", totalDistance / 1000.0f)); // 1 km in m
mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1000.0f)); // 1 km in m
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km);
}
break;
@@ -202,14 +204,14 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
mTotalDistanceView.setText(R.string.not_available);
mTotalDistanceUnitView.setText(null);
} else {
mTotalDistanceView.setText(String.format("%.2f", totalDistance / 1609.31f)); // 1 mile in m
mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1609.31f)); // 1 mile in m
mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_mile);
}
break;
}
mSpeedView.setText(String.format("%.1f", speed));
mCadenceView.setText(String.format("%d", cadence));
mSpeedView.setText(String.format(Locale.US, "%.1f", speed));
mCadenceView.setText(String.format(Locale.US, "%d", cadence));
mActivityView.setText(activity == RSCManagerCallbacks.ACTIVITY_RUNNING ? R.string.rsc_running : R.string.rsc_walking);
}
@@ -225,19 +227,19 @@ public class RSCActivity extends BleProfileServiceReadyActivity<RSCService.RSCBi
case SettingsFragment.SETTINGS_UNIT_KM_H:
case SettingsFragment.SETTINGS_UNIT_M_S:
if (distance < 100000) { // 1 km in cm
mDistanceView.setText(String.format("%.0f", distance / 100.0f));
mDistanceView.setText(String.format(Locale.US, "%.0f", distance / 100.0f));
mDistanceUnitView.setText(R.string.rsc_distance_unit_m);
} else {
mDistanceView.setText(String.format("%.2f", distance / 100000.0f));
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 100000.0f));
mDistanceUnitView.setText(R.string.rsc_distance_unit_km);
}
break;
case SettingsFragment.SETTINGS_UNIT_MPH:
if (distance < 160931) { // 1 mile in cm
mDistanceView.setText(String.format("%.0f", distance / 91.4392f));
mDistanceView.setText(String.format(Locale.US, "%.0f", distance / 91.4392f));
mDistanceUnitView.setText(R.string.rsc_distance_unit_yd);
} else {
mDistanceView.setText(String.format("%.2f", distance / 160931.23f));
mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 160931.23f));
mDistanceUnitView.setText(R.string.rsc_distance_unit_mile);
}
break;

View File

@@ -64,7 +64,7 @@ public class RSCManager extends BleManager<RSCManagerCallbacks> {
@Override
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
requests.push(Request.newEnableNotificationsRequest(mRSCMeasurementCharacteristic));
requests.add(Request.newEnableNotificationsRequest(mRSCMeasurementCharacteristic));
return requests;
}
@@ -84,8 +84,7 @@ public class RSCManager extends BleManager<RSCManagerCallbacks> {
@Override
public void onCharacteristicNotified(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
if (mLogSession != null)
Logger.a(mLogSession, RSCMeasurementParser.parse(characteristic));
Logger.a(mLogSession, "\"" + RSCMeasurementParser.parse(characteristic) + "\" received");
// Decode the new data
int offset = 0;
@@ -115,8 +114,8 @@ public class RSCManager extends BleManager<RSCManagerCallbacks> {
}
// Notify listener about the new measurement
mCallbacks.onMeasurementReceived(instantaneousSpeed, instantaneousCadence, totalDistance, instantaneousStrideLength, running ? RSCManagerCallbacks.ACTIVITY_RUNNING
: RSCManagerCallbacks.ACTIVITY_WALKING);
mCallbacks.onMeasurementReceived(gatt.getDevice(), instantaneousSpeed, instantaneousCadence, totalDistance, instantaneousStrideLength,
running ? RSCManagerCallbacks.ACTIVITY_RUNNING : RSCManagerCallbacks.ACTIVITY_WALKING);
}
};
}

View File

@@ -21,12 +21,14 @@
*/
package no.nordicsemi.android.nrftoolbox.rsc;
import android.bluetooth.BluetoothDevice;
import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
public interface RSCManagerCallbacks extends BleManagerCallbacks {
public static final int NOT_AVAILABLE = -1;
public static final int ACTIVITY_WALKING = 0;
public static final int ACTIVITY_RUNNING = 1;
int NOT_AVAILABLE = -1;
int ACTIVITY_WALKING = 0;
int ACTIVITY_RUNNING = 1;
public void onMeasurementReceived(float speed, int cadence, float distance, float strideLen, int activity);
void onMeasurementReceived(final BluetoothDevice device, float speed, int cadence, float distance, float strideLen, int activity);
}

View File

@@ -25,6 +25,7 @@ package no.nordicsemi.android.nrftoolbox.rsc;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -149,8 +150,9 @@ public class RSCService extends BleProfileService implements RSCManagerCallbacks
};
@Override
public void onMeasurementReceived(final float speed, final int cadence, final float totalDistance, final float strideLen, final int activity) {
public void onMeasurementReceived(final BluetoothDevice device, final float speed, final int cadence, final float totalDistance, final float strideLen, final int activity) {
final Intent broadcast = new Intent(BROADCAST_RSC_MEASUREMENT);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_SPEED, speed);
broadcast.putExtra(EXTRA_CADENCE, cadence);
broadcast.putExtra(EXTRA_TOTAL_DISTANCE, totalDistance);

View File

@@ -21,6 +21,7 @@
*/
package no.nordicsemi.android.nrftoolbox.template;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -133,7 +134,7 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
}
@Override
public void onServicesDiscovered(boolean optionalServicesFound) {
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
// this may notify user or show some views
}

View File

@@ -66,7 +66,7 @@ public class TemplateManager extends BleManager<TemplateManagerCallbacks> {
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
// TODO initialize your device, enable required notifications and indications, write what needs to be written to start working
requests.push(Request.newEnableNotificationsRequest(mCharacteristic));
requests.add(Request.newEnableNotificationsRequest(mCharacteristic));
return requests;
}
@@ -99,8 +99,7 @@ public class TemplateManager extends BleManager<TemplateManagerCallbacks> {
// TODO this method is called when a notification has been received
// This method may be removed from this class if not required
if (mLogSession != null)
Logger.a(mLogSession, TemplateParser.parse(characteristic));
Logger.a(mLogSession, "\"" + TemplateParser.parse(characteristic) + "\" received");
int value;
final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
@@ -110,7 +109,7 @@ public class TemplateManager extends BleManager<TemplateManagerCallbacks> {
value = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 1);
}
//This will send callback to the Activity when new value is received from HR device
mCallbacks.onSampleValueReceived(value);
mCallbacks.onSampleValueReceived(gatt.getDevice(), value);
}
@Override

View File

@@ -21,6 +21,8 @@
*/
package no.nordicsemi.android.nrftoolbox.template;
import android.bluetooth.BluetoothDevice;
import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
/**
@@ -32,10 +34,11 @@ public interface TemplateManagerCallbacks extends BleManagerCallbacks {
/**
* Called when a value is received.
*
*
* @param device a device from which the value was obtained
* @param value
* the new value
*/
public void onSampleValueReceived(int value);
void onSampleValueReceived(final BluetoothDevice device, int value);
}

View File

@@ -25,6 +25,7 @@ package no.nordicsemi.android.nrftoolbox.template;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -112,8 +113,9 @@ public class TemplateService extends BleProfileService implements TemplateManage
}
@Override
public void onSampleValueReceived(final int value) {
public void onSampleValueReceived(final BluetoothDevice device, final int value) {
final Intent broadcast = new Intent(BROADCAST_TEMPLATE_MEASUREMENT);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_DATA, value);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);

View File

@@ -271,7 +271,7 @@ public class UARTActivity extends BleProfileServiceReadyActivity<UARTService.UAR
}
@Override
public void onServicesDiscovered(final boolean optionalServicesFound) {
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
// do nothing
}

View File

@@ -33,6 +33,7 @@ import java.util.LinkedList;
import java.util.Queue;
import java.util.UUID;
import no.nordicsemi.android.log.Logger;
import no.nordicsemi.android.nrftoolbox.profile.BleManager;
public class UARTManager extends BleManager<UARTManagerCallbacks> {
@@ -66,7 +67,7 @@ public class UARTManager extends BleManager<UARTManagerCallbacks> {
@Override
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
final LinkedList<Request> requests = new LinkedList<>();
requests.push(Request.newEnableNotificationsRequest(mTXCharacteristic));
requests.add(Request.newEnableNotificationsRequest(mTXCharacteristic));
return requests;
}
@@ -106,7 +107,9 @@ public class UARTManager extends BleManager<UARTManagerCallbacks> {
final byte[] buffer = mOutgoingBuffer;
if (mBufferOffset == buffer.length) {
try {
mCallbacks.onDataSent(new String(buffer, "UTF-8"));
final String data = new String(buffer, "UTF-8");
Logger.a(mLogSession, "\"" + data + "\" sent");
mCallbacks.onDataSent(gatt.getDevice(), data);
} catch (final UnsupportedEncodingException e) {
// do nothing
}
@@ -124,7 +127,8 @@ public class UARTManager extends BleManager<UARTManagerCallbacks> {
@Override
public void onCharacteristicNotified(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
final String data = characteristic.getStringValue(0);
mCallbacks.onDataReceived(data);
Logger.a(mLogSession, "\"" + data + "\" received");
mCallbacks.onDataReceived(gatt.getDevice(), data);
}
};

View File

@@ -22,11 +22,13 @@
package no.nordicsemi.android.nrftoolbox.uart;
import android.bluetooth.BluetoothDevice;
import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
public interface UARTManagerCallbacks extends BleManagerCallbacks {
public void onDataReceived(final String data);
void onDataReceived(final BluetoothDevice device, final String data);
public void onDataSent(final String data);
void onDataSent(final BluetoothDevice device, final String data);
}

View File

@@ -22,10 +22,8 @@
package no.nordicsemi.android.nrftoolbox.uart;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
@@ -33,7 +31,6 @@ import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
@@ -53,21 +50,21 @@ public class UARTNewConfigurationDialogFragment extends DialogFragment implement
* @param name the name
* @param duplicate true if configuration is to be duplicated
*/
public void onNewConfiguration(final String name, final boolean duplicate);
void onNewConfiguration(final String name, final boolean duplicate);
/**
* Renames the current configuration with given name.
* @param newName the new name
*/
public void onRenameConfiguration(final String newName);
void onRenameConfiguration(final String newName);
}
@Override
public void onAttach(final Activity activity) {
super.onAttach(activity);
public void onAttach(final Context context) {
super.onAttach(context);
if (activity instanceof NewConfigurationDialogListener) {
mListener = (NewConfigurationDialogListener) activity;
if (context instanceof NewConfigurationDialogListener) {
mListener = (NewConfigurationDialogListener) context;
} else {
throw new IllegalArgumentException("The parent activity must implement NewConfigurationDialogListener");
}

View File

@@ -25,6 +25,7 @@ package no.nordicsemi.android.nrftoolbox.uart;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -143,8 +144,8 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
}
@Override
public void onDeviceConnected() {
super.onDeviceConnected();
public void onDeviceConnected(final BluetoothDevice device) {
super.onDeviceConnected(device);
sendMessageToWearables(Constants.UART.DEVICE_CONNECTED, notNull(getDeviceName()));
}
@@ -154,14 +155,14 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
}
@Override
public void onDeviceDisconnected() {
super.onDeviceDisconnected();
public void onDeviceDisconnected(final BluetoothDevice device) {
super.onDeviceDisconnected(device);
sendMessageToWearables(Constants.UART.DEVICE_DISCONNECTED, notNull(getDeviceName()));
}
@Override
public void onLinklossOccur() {
super.onLinklossOccur();
public void onLinklossOccur(final BluetoothDevice device) {
super.onLinklossOccur(device);
sendMessageToWearables(Constants.UART.DEVICE_LINKLOSS, notNull(getDeviceName()));
}
@@ -172,24 +173,23 @@ public class UARTService extends BleProfileService implements UARTManagerCallbac
}
@Override
public void onDataReceived(final String data) {
Logger.a(getLogSession(), "\"" + data + "\" received");
public void onDataReceived(final BluetoothDevice device, final String data) {
final Intent broadcast = new Intent(BROADCAST_UART_RX);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_DATA, data);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
// send the data received to other apps, e.g. the Tasker
final Intent globalBroadcast = new Intent(ACTION_RECEIVE);
globalBroadcast.putExtra(BluetoothDevice.EXTRA_DEVICE, getBluetoothDevice());
globalBroadcast.putExtra(Intent.EXTRA_TEXT, data);
sendBroadcast(globalBroadcast);
}
@Override
public void onDataSent(final String data) {
Logger.a(getLogSession(), "\"" + data + "\" sent");
public void onDataSent(final BluetoothDevice device, final String data) {
final Intent broadcast = new Intent(BROADCAST_UART_TX);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_DATA, data);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
}

View File

@@ -114,6 +114,7 @@
style="@style/Widget.ListTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cgms_value_unit"
android:layout_alignParentRight="true"
android:layout_marginRight="4dp"/>
</RelativeLayout>

View File

@@ -110,6 +110,7 @@
style="@style/Widget.ListTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cgms_value_unit"
android:layout_alignParentRight="true"
android:layout_marginRight="4dp"/>
</RelativeLayout>

View File

@@ -20,52 +20,35 @@
~ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
~ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:paddingBottom="2dp"
android:paddingEnd="4dp"
android:paddingStart="?android:attr/listPreferredItemPaddingLeft"
android:paddingTop="2dp"
android:orientation="horizontal">
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:paddingTop="2dp">
<LinearLayout
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItem"/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItem"/>
<TextView
android:id="@+id/details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="12sp"
android:text="@string/cgms_item_summary"/>
</LinearLayout>
<TextView
android:id="@+id/details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/time"
android:layout_marginTop="2dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="12sp"/>
<TextView
android:id="@+id/cgms_concentration"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_centerVertical="true"
android:gravity="right"
android:textAppearance="?android:attr/textAppearanceLarge"
android:paddingEnd="?android:attr/listPreferredItemPaddingLeft"/>
<TextView
android:id="@+id/cgms_unit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/cgms_value_unit"/>
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
</RelativeLayout>

View File

@@ -23,7 +23,5 @@
<resources>
<string name="cgms_feature_title_long">CGMS</string>
<string name="text_cgms_interval">GCM updates are notified every minute</string>
<string name="cgms_item_summary">Glucose concentration level</string>
<dimen name="cgms_feature_title_long_margin">-16dp</dimen>
</resources>

View File

@@ -22,16 +22,15 @@
-->
<resources>
<string name="cgms_feature_title">CGMS</string>
<string name="cgms_feature_title_long">CONT. GLUCOSE MONITOR</string>
<dimen name="cgms_feature_title_long_margin">-180dp</dimen>
<string name="cgms_feature_title">CGMS</string>
<string name="cgms_feature_title_long">CONT. GLUCOSE MONITOR</string>
<dimen name="cgms_feature_title_long_margin">-180dp</dimen>
<string name="cgms_default_name">DEFAULT CGMS</string>
<string name="cgms_value_unit">mg/dL</string>
<string name="cgms_position_label">sensor position</string>
<string name="cgms_default_name">DEFAULT CGMS</string>
<string name="cgms_value_unit">mg/dL</string>
<string name="cgms_details">Sequence number: %d</string>
<string name="cgms_about_text">CGMS (Continuous Glucode Monitoring Service) profile allows you to connect to your Continuous Glucose Monitoring sensor.
It shows you the continuous glucose measurement on the table.</string>
<string name="text_cgms_interval">GCM updates are notified every minute</string>
<string name="cgms_item_summary">Glucose concentration level</string>
It shows you the continuous glucose measurement on the table. A new record should show up on the list every minute. You may also request all, first or the last
record using buttons below the list.</string>
</resources>

View File

@@ -25,11 +25,8 @@ package no.nordicsemi.android.nrftoolbox.uart;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import java.util.LinkedList;
import java.util.Queue;
import java.util.UUID;
@@ -82,7 +79,7 @@ public class UARTProfile extends BleProfile {
// We don't want to enable notifications on TX characteristic as we are not showing them here. A watch may be just used to send data. At least now.
// final LinkedList<BleManager.Request> requests = new LinkedList<>();
// requests.push(BleManager.Request.newEnableNotificationsRequest(mTXCharacteristic));
// requests.add(BleManager.Request.newEnableNotificationsRequest(mTXCharacteristic));
// return requests;
return null;
}