private void calculateAcceleration( BluetoothGattCharacteristic characteristic, BluetoothGatt gatt) { /* * The accelerometer has the range [-2g, 2g] with unit (1/64)g. * * To convert from unit (1/64)g to unit g we divide by 64. * * (g = 9.81 m/s^2) * * The z value is multiplied with -1 to coincide * with how we have arbitrarily defined the positive y direction. * (illustrated by the apps accelerometer image) * * -32 = -2g * -16 = -1g * 0 = 0g * 16 = 1g * 32 = 2g * */ int accX = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT8, 0); int accY = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT8, 1); int accZ = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT8, 2) * -1; System.out.println("Acc X: " + accX + " Y: " + accY + " Z: " + accZ); Acceleration a = new Acceleration(accX, accY, accZ); acc.put(gatt.getDevice().getAddress(), a); setChanged(); notifyObservers(getSensorData(gatt)); }
private void displayData(final BluetoothGattCharacteristic characteristic, Characteristiques ch) { switch (characteristic.getUuid().toString()) { case FlowerPowerConstants.CHARACTERISTIC_UUID_TEMPERATURE: int temperature = valueMapper.mapTemperature( characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 0)); ch.setValue(temperature + ""); System.err.println("Temp " + ch.getValue()); break; case FlowerPowerConstants.CHARACTERISTIC_UUID_SUNLIGHT: double luminosite = valueMapper.mapSunlight( characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 0)); ch.setValue(luminosite + ""); System.err.println("Display Sunlight" + ch.getValue()); break; case FlowerPowerConstants.CHARACTERISTIC_UUID_SOIL_MOISTURE: double humidite = valueMapper.mapSoilMoisture( characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 0)); ch.setValue(humidite + ""); System.err.println("Display Soil Moisture " + ch.getValue()); break; default: break; } MainActivity.adapter.notifyDataSetChanged(); myView.invalidate(); }
@Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic arg0) { if (gatt != btGatt) { return; } if (!arg0.getUuid().equals(HEART_RATE_MEASUREMENT_CHARAC)) { System.err.println("onCharacteristicChanged(" + arg0 + ") != HEART_RATE ??"); return; } int length = arg0.getValue().length; if (length == 0) { System.err.println("length = 0"); return; } if (isHeartRateInUINT16(arg0.getValue()[0])) { hrValue = arg0.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 1); } else { hrValue = arg0.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 1); } hrTimestamp = System.currentTimeMillis(); if (mIsConnecting) { reportConnected(true); } }
@Override protected void onCharacteristicIndicated( final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { if (mLogSession != null) Logger.a(mLogSession, RecordAccessControlPointParser.parse(characteristic)); // Record Access Control Point characteristic int offset = 0; final int opCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); offset += 2; // skip the operator 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); mCallbacks.onNumberOfRecordsRequested(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(); } } 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); 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; } }
/** * Getting the Energy Expended * * @param characteristic * @return String */ public static String getEnergyExpended(BluetoothGattCharacteristic characteristic) { int eeval = 0; if (isEEpresent(characteristic.getValue()[0])) { if (isHeartRateInUINT16(characteristic.getValue()[0])) { eeval = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 3); } else { eeval = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 2); } } return String.valueOf(eeval); }
@Override public final void onCharacteristicChanged( final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { final String data = ParserUtils.parse(characteristic); if (isBatteryLevelCharacteristic(characteristic)) { 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); } 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; if (notifications) { Logger.i( mLogSession, "Notification received from " + characteristic.getUuid() + ", value: " + data); onCharacteristicNotified(gatt, characteristic); } else { // indications Logger.i( mLogSession, "Indication received from " + characteristic.getUuid() + ", value: " + data); onCharacteristicIndicated(gatt, characteristic); } } }
private void broadcastUpdate( final String action, final BluetoothGattCharacteristic characteristic) { final Intent intent = new Intent(action); // This is special handling for the Heart Rate Measurement profile. Data parsing is // carried out as per profile specifications: // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { int flag = characteristic.getProperties(); int format = -1; if ((flag & 0x01) != 0) { format = BluetoothGattCharacteristic.FORMAT_UINT16; Log.d(TAG, "Heart rate format UINT16."); } else { format = BluetoothGattCharacteristic.FORMAT_UINT8; Log.d(TAG, "Heart rate format UINT8."); } final int heartRate = characteristic.getIntValue(format, 1); Log.d(TAG, String.format("Received heart rate: %d", heartRate)); intent.putExtra(EXTRA_DATA, String.valueOf(heartRate)); } else { // For all other profiles, writes the data formatted in HEX. final byte[] data = characteristic.getValue(); if (data != null && data.length > 0) { final StringBuilder stringBuilder = new StringBuilder(data.length); for (byte byteChar : data) stringBuilder.append(String.format("%02X ", byteChar)); intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString()); } } sendBroadcast(intent); }
private void broadcastUpdate( final String action, final BluetoothGattCharacteristic characteristic) { final Intent intent = new Intent(action); if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { int flag = characteristic.getProperties(); int format = -1; if ((flag & 0x01) != 0) { format = BluetoothGattCharacteristic.FORMAT_UINT16; } else { format = BluetoothGattCharacteristic.FORMAT_UINT8; } final int heartRate = characteristic.getIntValue(format, 1); LogUtil.info(TAG, "心率数据Received heart rate: %d" + heartRate); LogUtil.info(TAG, String.format("Received heart rate: %d", heartRate)); intent.putExtra(EXTRA_DATA, receiveData); } else { // 脂肪秤和血糖仪设备数据返回 final byte[] data = characteristic.getValue(); if (data != null && data.length > 0) { String s = FatScaleDataUtil.byteToHexStringFormat(data); LogUtil.info(TAG, "原始数据:" + s); if (DEVICE_TYPE == 1) { intent.putExtra(EXTRA_DATA, s); } else { intent.putExtra(EXTRA_DATA, receiveData); } } } sendBroadcast(intent); }
/** * Getting the RR-Interval * * @param characteristic * @return ArrayList */ public static ArrayList<Integer> getRRInterval(BluetoothGattCharacteristic characteristic) { ArrayList<Integer> rrinterval = new ArrayList<Integer>(); int length = characteristic.getValue().length; if (isEEpresent(characteristic.getValue()[0])) { if (isHeartRateInUINT16(characteristic.getValue()[0])) { if (isRRintpresent(characteristic.getValue()[0])) { int startoffset = 5; for (int i = startoffset; i < length; i += 2) { rrinterval.add( characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, i)); } } } else { if (isRRintpresent(characteristic.getValue()[0])) { int startoffset = 4; for (int i = startoffset; i < length; i += 2) { rrinterval.add( characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, i)); } } } } else { if (isHeartRateInUINT16(characteristic.getValue()[0])) { if (isRRintpresent(characteristic.getValue()[0])) { int startoffset = 3; for (int i = startoffset; i < length; i += 2) { rrinterval.add( characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, i)); } } } else { if (isRRintpresent(characteristic.getValue()[0])) { int startoffset = 2; for (int i = startoffset; i < length; i += 2) { rrinterval.add( characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, i)); } } } } return rrinterval; }
/** * Getting the heart rate * * @param characteristic * @return String */ public static String getHeartRate(BluetoothGattCharacteristic characteristic) { int format = -1; if (isHeartRateInUINT16(characteristic.getValue()[0])) { format = BluetoothGattCharacteristic.FORMAT_UINT16; } else { format = BluetoothGattCharacteristic.FORMAT_UINT8; } final int heartRate = characteristic.getIntValue(format, 1); return String.valueOf(heartRate); }
@Override public void onCharacteristicNotified( final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { if (mLogSession != null) Logger.a(mLogSession, CSCMeasurementParser.parse(characteristic)); // Decode the new data int offset = 0; final int flags = characteristic.getValue()[offset]; // 1 byte offset += 1; final boolean wheelRevPresent = (flags & WHEEL_REVOLUTIONS_DATA_PRESENT) > 0; final boolean crankRevPreset = (flags & CRANK_REVOLUTION_DATA_PRESENT) > 0; if (wheelRevPresent) { final int wheelRevolutions = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, offset); offset += 4; final int lastWheelEventTime = characteristic.getIntValue( BluetoothGattCharacteristic.FORMAT_UINT16, offset); // 1/1024 s offset += 2; // Notify listener about the new measurement mCallbacks.onWheelMeasurementReceived(wheelRevolutions, lastWheelEventTime); } if (crankRevPreset) { final int crankRevolutions = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); offset += 2; final int lastCrankEventTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); // offset += 2; // Notify listener about the new measurement mCallbacks.onCrankMeasurementReceived(crankRevolutions, lastCrankEventTime); } }
@Override public SimpleKeysStatus parse(BluetoothGattCharacteristic c) { /* * The key state is encoded into 1 unsigned byte. * bit 0 designates the right key. * bit 1 designates the left key. * bit 2 designates the side key. * * Weird, in the userguide left and right are opposite. */ int encodedInteger = c.getIntValue(FORMAT_UINT8, 0); return SimpleKeysStatus.values()[encodedInteger % 4]; }
@Override public void onCharacteristicChanged( BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { Log.d("characteristic=" + characteristic.getUuid()); int format; int flag = characteristic.getProperties(); if ((flag & 0x01) != 0) { format = BluetoothGattCharacteristic.FORMAT_UINT16; } else { format = BluetoothGattCharacteristic.FORMAT_UINT8; } int previousValue = mLastValue; int value = characteristic.getIntValue(format, 1); if (value < 50) { // This is probably a false measurement, consider this as a disconnect if (mStatus == Status.CONNECTED) { // Disconnect onDisconnect(); } return; } mLastValue = value; Log.d("heartRate=" + mLastValue); if (mStatus != Status.CONNECTED) { mStatus = Status.CONNECTED; // Inform listeners mListeners.dispatch( new Dispatcher<HeartRateListener>() { @Override public void dispatch(HeartRateListener listener) { listener.onConnected(); } }); } if (previousValue != mLastValue) { // Inform listeners mListeners.dispatch( new Dispatcher<HeartRateListener>() { @Override public void dispatch(HeartRateListener listener) { listener.onHeartRateChange(mLastValue); } }); } }
@Override public float[] parse(final BluetoothGattCharacteristic c) { /* * The accelerometer has the range [-2g, 2g] with unit (1/64)g. * * To convert from unit (1/64)g to unit g we divide by 64. * * (g = 9.81 m/s^2) * * The z value is multiplied with -1 to coincide * with how we have arbitrarily defined the positive y direction. * (illustrated by the apps accelerometer image) * */ Integer x = c.getIntValue(FORMAT_SINT8, 0); Integer y = c.getIntValue(FORMAT_SINT8, 1); Integer z = c.getIntValue(FORMAT_SINT8, 2) * -1; double scaledX = x / 64.0; double scaledY = y / 64.0; double scaledZ = z / 64.0; return new float[] {(float) scaledX, (float) scaledY, (float) scaledZ}; }
private void calculateHumidity(BluetoothGattCharacteristic characteristic, BluetoothGatt gatt) { String address = gatt.getDevice().getAddress(); /*calculate humididty*/ Integer lowerTempByte = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0); Integer upperTempByte = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 1); Integer lowerHumByte = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 2); Integer upperHumByte = characteristic.getIntValue( BluetoothGattCharacteristic.FORMAT_UINT8, 3); // Note: interpret MSB as unsigned. // Humidity int hum = (upperHumByte << 8) + lowerHumByte; hum = hum - (hum % 4); double humi = (-6f) + 125f * (hum / 65535f); humidity.put(address, humi); // Temperature int temp = (upperTempByte << 8) + lowerTempByte; double t = -46.85f + (175.72f / 65536f) * (float) temp; temperature.put(address, t); System.out.println("Humidity: " + humidity); System.out.println("Temperature: " + temperature); SensorData sd = getSensorData(gatt); setChanged(); notifyObservers(sd); }
private void broadcastUpdate( final String action, final BluetoothGattCharacteristic characteristic, String device) { final Intent intent = new Intent(action); if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { int flag = characteristic.getProperties(); int format = -1; if ((flag & 0x01) != 0) { format = BluetoothGattCharacteristic.FORMAT_UINT16; Log.d(TAG, "Heart rate format UINT16."); } else { format = BluetoothGattCharacteristic.FORMAT_UINT8; Log.d(TAG, "Heart rate format UINT8."); } final int heartRate = characteristic.getIntValue(format, 1); System.out.println("Received heart rate: %d" + heartRate); Log.d(TAG, String.format("Received heart rate: %d", heartRate)); intent.putExtra(EXTRA_DATA, String.valueOf(heartRate)); } else if (BATTERY_CHACTER_UUID.equals(characteristic.getUuid())) { final byte[] data = characteristic.getValue(); if (data != null && data.length > 0) { final StringBuilder stringBuilder = new StringBuilder(data.length); for (byte byteChar : data) stringBuilder.append(String.format("%02X ", byteChar)); Log.e(TAG, "############################broadcastUpdate : " + data[0]); intent.putExtra(BATTERY_DATA, data); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); } } else { // For all other profiles, writes the data formatted in HEX. /*final byte[] data = characteristic.getValue(); for (int i = 0; i < data.length; i++) { Log.v("ww", "sa:" + data[i]); } if (data != null && data.length > 0) { intent.putExtra(EXTRA_DATA, data); }*/ final byte[] data = characteristic.getValue(); if (data != null && data.length > 0) { final StringBuilder stringBuilder = new StringBuilder(data.length); for (byte byteChar : data) stringBuilder.append(String.format("%02X ", byteChar)); intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString()); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); } } sendBroadcast(intent); }
@Override public final void onCharacteristicRead( final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) { if (status == BluetoothGatt.GATT_SUCCESS) { Logger.i( mLogSession, "Read Response received from " + characteristic.getUuid() + ", value: " + ParserUtils.parse(characteristic)); if (isBatteryLevelCharacteristic(characteristic)) { final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0); Logger.a(mLogSession, "Battery level received: " + batteryValue + "%"); mCallbacks.onBatteryValueReceived(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. if (!setBatteryNotifications(true)) nextRequest(); } else { // The value has been read. Notify the manager and proceed with the initialization queue. onCharacteristicRead(gatt, characteristic); nextRequest(); } } 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); } } else { DebugLogger.e(TAG, "onCharacteristicRead error " + status); onError(ERROR_READ_CHARACTERISTIC, status); } }
/** * Parses the date and time info. This data has 7 bytes * * @param characteristic * @param offset offset to start reading the time * @return time in human readable format */ /* package */ static String parse( final BluetoothGattCharacteristic characteristic, final int offset) { final int year = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); final int month = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 2); final int day = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 3); final int hours = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 4); final int minutes = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 5); final int seconds = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 6); final Calendar calendar = Calendar.getInstance(); calendar.set(year, month - 1, day, hours, minutes, seconds); return String.format(Locale.US, "%1$te %1$tb %1$tY, %1$tH:%1$tM:%1$tS", calendar); }
private void broadcastUpdate( final String action, final BluetoothGattCharacteristic characteristic) { final Intent intent = new Intent(action); // This is special handling for the Heart Rate Measurement profile. Data parsing is // carried out as per profile specifications: // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { int flag = characteristic.getProperties(); int format = -1; if ((flag & 0x01) != 0) { format = BluetoothGattCharacteristic.FORMAT_UINT16; Log.d(TAG, "Heart rate format UINT16."); } else { format = BluetoothGattCharacteristic.FORMAT_UINT8; Log.d(TAG, "Heart rate format UINT8."); } final int heartRate = characteristic.getIntValue(format, 1); Log.d(TAG, String.format("Received heart rate: %d", heartRate)); intent.putExtra(EXTRA_DATA, String.valueOf(heartRate)); } else { // For all other profiles, writes the data formatted in HEX. final byte[] data = characteristic.getValue(); if (data != null && data.length > 0) { final StringBuilder stringBuilder = new StringBuilder(data.length); for (byte byteChar : data) stringBuilder.append(String.format("%02X ", byteChar)); intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString()); if (characteristic.getUuid().toString().equals(SampleGattAttributes.DEBUG_PACKET_CHAR)) { log28.append("\n" + new String(data) + "\n" + stringBuilder.toString() + "\n"); } else if (characteristic .getUuid() .toString() .equals(SampleGattAttributes.QUAT_PACKET_CHAR)) { log26.append("\n" + new String(data) + "\n" + stringBuilder.toString() + "\n"); } else if (characteristic .getUuid() .toString() .equals(SampleGattAttributes.DATA_PACKET_CHAR)) { log27.append("\n" + new String(data) + "\n" + stringBuilder.toString() + "\n"); String dataType = stringBuilder.substring(3, 5); Log.d(TAG, "String Subset: " + dataType); switch (dataType) { case "00": // a log27_a.append("\n" + new String(data) + "\n" + stringBuilder.toString() + "\n"); break; case "01": // g log27_g.append("\n" + new String(data) + "\n" + stringBuilder.toString() + "\n"); break; case "03": // q log27_q.append("\n" + new String(data) + "\n" + stringBuilder.toString() + "\n"); break; case "04": // e log27_e.append("\n" + new String(data) + "\n" + stringBuilder.toString() + "\n"); break; case "06": // h log27_h.append("\n" + new String(data) + "\n" + stringBuilder.toString() + "\n"); break; } } } } sendBroadcast(intent); }
@Override public void onCharacteristicNotified( BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { final UUID uuid = characteristic.getUuid(); if (GM_CHARACTERISTIC.equals(uuid)) { if (mLogSession != null) Logger.a(mLogSession, GlucoseMeasurementParser.parse(characteristic)); int offset = 0; final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); offset += 1; final boolean timeOffsetPresent = (flags & 0x01) > 0; final boolean typeAndLocationPresent = (flags & 0x02) > 0; final int concentrationUnit = (flags & 0x04) > 0 ? GlucoseRecord.UNIT_molpl : GlucoseRecord.UNIT_kgpl; final boolean sensorStatusAnnunciationPresent = (flags & 0x08) > 0; final boolean contextInfoFollows = (flags & 0x10) > 0; // create and fill the new record final GlucoseRecord record = new GlucoseRecord(); record.sequenceNumber = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); offset += 2; final int year = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); final int month = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 2) - 1; // months are 1-based final int day = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 3); final int hours = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 4); final int minutes = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 5); final int seconds = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 6); offset += 7; final Calendar calendar = Calendar.getInstance(); calendar.set(year, month, day, hours, minutes, seconds); record.time = calendar; if (timeOffsetPresent) { // time offset is ignored in the current release record.timeOffset = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16, offset); offset += 2; } if (typeAndLocationPresent) { record.glucoseConcentration = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset); record.unit = concentrationUnit; final int typeAndLocation = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 2); record.type = (typeAndLocation & 0xF0) >> 4; // TODO this way or around? record.sampleLocation = (typeAndLocation & 0x0F); offset += 3; } if (sensorStatusAnnunciationPresent) { record.status = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); } // This allows you to check other values that are not provided by the Nordic // Semiconductor's Glucose Service in SDK 4.4.2. // record.status = 0x1A; // record.context = new GlucoseRecord.MeasurementContext(); // record.context.carbohydrateId = 1; // record.context.carbohydrateUnits = 0.23f; // record.context.meal = 2; // record.context.tester = 2; // record.context.health = 4; // the following values are not implemented yet (see // ExpandableRecordAdapter#getChildrenCount() and #getChild(...) // record.context.exerciseDuration = 3600; // record.context.exerciseIntensity = 45; // record.context.medicationId = 3; // record.context.medicationQuantity = 0.03f; // record.context.medicationUnit = GlucoseRecord.MeasurementContext.UNIT_kg; // record.context.HbA1c = 213.3f; // data set modifications must be done in UI thread mHandler.post( new Runnable() { @Override public void run() { // insert the new record to storage mRecords.put(record.sequenceNumber, record); // if there is no context information following the measurement data, notify // callback about the new record if (!contextInfoFollows) mCallbacks.onDatasetChanged(); } }); } else if (GM_CONTEXT_CHARACTERISTIC.equals(uuid)) { if (mLogSession != null) Logger.a(mLogSession, GlucoseMeasurementContextParser.parse(characteristic)); int offset = 0; final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); offset += 1; final boolean carbohydratePresent = (flags & 0x01) > 0; final boolean mealPresent = (flags & 0x02) > 0; final boolean testerHealthPresent = (flags & 0x04) > 0; final boolean exercisePresent = (flags & 0x08) > 0; final boolean medicationPresent = (flags & 0x10) > 0; final int medicationUnit = (flags & 0x20) > 0 ? GlucoseRecord.MeasurementContext.UNIT_l : GlucoseRecord.MeasurementContext.UNIT_kg; final boolean hbA1cPresent = (flags & 0x40) > 0; final boolean moreFlagsPresent = (flags & 0x80) > 0; final int sequenceNumber = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); offset += 2; final GlucoseRecord record = mRecords.get(sequenceNumber); if (record == null) { DebugLogger.w( TAG, "Context information with unknown sequence number: " + sequenceNumber); return; } final GlucoseRecord.MeasurementContext context = new GlucoseRecord.MeasurementContext(); record.context = context; if (moreFlagsPresent) offset += 1; if (carbohydratePresent) { context.carbohydrateId = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); context.carbohydrateUnits = characteristic.getFloatValue( BluetoothGattCharacteristic.FORMAT_SFLOAT, offset + 1); offset += 3; } if (mealPresent) { context.meal = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); offset += 1; } if (testerHealthPresent) { final int testerHealth = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); context.tester = (testerHealth & 0xF0) >> 4; context.health = (testerHealth & 0x0F); offset += 1; } if (exercisePresent) { context.exerciseDuration = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); context.exerciseIntensity = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 2); offset += 3; } if (medicationPresent) { context.medicationId = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); context.medicationQuantity = characteristic.getFloatValue( BluetoothGattCharacteristic.FORMAT_SFLOAT, offset + 1); context.medicationUnit = medicationUnit; offset += 3; } if (hbA1cPresent) { context.HbA1c = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset); } // notify callback about the new record mCallbacks.onDatasetChanged(); } }