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;
          }
        }
Esempio n. 5
0
  /**
   * 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);
  }
Esempio n. 6
0
    @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);
 }
Esempio n. 9
0
 /**
  * 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;
 }
Esempio n. 10
0
  /**
   * 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);
  }
Esempio n. 17
0
    @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);
  }
Esempio n. 19
0
  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();
          }
        }