/*
* Copyright (C) 2014 TU Darmstadt, Hessen, Germany.
* Department of Computer Science Databases and Distributed Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*/
package de.tudarmstadt.dvs.myhealthassistant.myhealthhub.sensormodules.cardiovascular;
import android.util.Log;
/**
* /**
* An implementation of a Sensor MessageParser for Polar Wearlink Bluetooth HRM.
*
* Polar Bluetooth Wearlink packet example;
* Hdr Len Chk Seq Status HeartRate RRInterval_16-bits
* FE 08 F7 06 F1 48 03 64
* where;
* Hdr always = 254 (0xFE),
* Chk = 255 - Len
* Seq range 0 to 15
* Status = Upper nibble may be battery voltage
* bit 0 is Beat Detection flag.
*
* Additional packet examples;
* FE 08 F7 06 F1 48 03 64
* FE 0A F5 06 F1 48 03 64 03 70
*
*
* @author Christian Seeger
*
*/
public class PolarHRModuleUtils {
// for debugging
private static boolean D = false;
private static String TAG = "PolarHRModuleUtils";
public final int INVALID_HEART_RATE = -1;
private byte[] packetBuffer;
private int packetBufferPointer;
private final int MAX_PACKET_SIZE = 16; // for Polar
/**
*
*/
public PolarHRModuleUtils() {
packetBuffer = new byte[MAX_PACKET_SIZE];
}
public int getHeartRate(byte[] packet, int length) {
//if(D)printPacketInHex(length, packet, "Incoming Polar HR packet: ");
int heartRate = INVALID_HEART_RATE;
if(packetValid(packet, 0)) {
heartRate = packet[5] & 0xFF;
if (D)
Log.d(TAG, "Heart rate found: " + heartRate);
}
return heartRate;
}
public int incomingPacket(byte[] packet, int length) {
if(D) printPacketInHex(length, packet, "Incoming packet: ");
int heartRate = INVALID_HEART_RATE;
// if buffer is empty
if(packetBufferPointer==0) {
// check for valid packet
if(packetValid(packet, 0)) {
//if(D) printPacketInHex(length, packet, "Process single packet: ");
heartRate = packet[5] & 0xFF;
// add to packet buffer
} else {
System.arraycopy(packet, 0, packetBuffer, packetBufferPointer, length);
packetBufferPointer = length;
}
} else {
//TODO make it better
// avoid buffer indexOutOfBound Exception
if(packetBufferPointer+length>MAX_PACKET_SIZE) {
if(D) Log.d(TAG, "avoid indexOutOfBoundException");
// empty buffer
packetBufferPointer = 0;
packetBuffer = new byte[MAX_PACKET_SIZE];
return INVALID_HEART_RATE;
}
// Concatenate packet to buffer
System.arraycopy(packet, 0, packetBuffer, packetBufferPointer, length);
packetBufferPointer += length;
// check for valid packet
if(packetValid(packetBuffer, 0)) {
//if(D) printPacketInHex(packetBuffer.length, packetBuffer, "Process concat packet: ");
heartRate = packetBuffer[5] & 0xFF;
// empty buffer
packetBufferPointer = 0;
packetBuffer = new byte[MAX_PACKET_SIZE];
}
}
return heartRate;
}
/**
* Applies Polar packet validation rules to buffer. Polar packets are
* checked for following; offset 0 = header byte, 254 (0xFE). offset 1 =
* packet length byte, 8, 10, 12, 14. offset 2 = check byte, 255 - packet
* length. offset 3 = sequence byte, range from 0 to 15.
*
* @param an
* array of bytes to parse
* @param buffer
* offset to beginning of packet.
* @return whether buffer has a valid packet at offset i
*/
private boolean packetValid(byte[] buffer, int i) {
if(buffer.length-i >= 6 ) {
boolean headerValid = (buffer[i] & 0xFF) == 0xFE;
boolean checkbyteValid = (buffer[i + 2] & 0xFF) == (0xFF - (buffer[i + 1] & 0xFF));
boolean sequenceValid = (buffer[i + 3] & 0xFF) < 16;
return headerValid && checkbyteValid && sequenceValid;
} else {
return false;
}
}
/**
* Searches buffer for the beginning of a valid packet.
*
* @param an array of bytes to parse
* @return index to beginning of good packet, or -1 if none found.
*/
public int findNextAlignment(byte[] buffer) {
// Minimum length Polar packets is 8, so stop search 8 bytes before buffer ends.
for (int i = 0; i < buffer.length - 8; i++) {
if (packetValid(buffer,i)) {
return i;
}
}
return -1;
}
public void printPacketInHex(int bytes, byte[] buffer, String info) {
String text = "";
for(int i = 0; i < bytes; i++){
text += i+": "+java.lang.Integer.toHexString(buffer[i]&0xff)+" |";
}
if(D)Log.d(TAG, info+" "+text);
}
public void printPacket(int bytes, byte[] buffer, String info) {
String text = "";
for(int i = 0; i < bytes; i++){
text += i+": "+buffer[i]+" |";
}
Log.d(TAG, info+" "+text);
}
}