I have set up a bluetooth connection and found the data does not match on the receiver (visually through scope). The issue appears to be the data conversion int to byte.
buffer[0] = (byte) r_value
Where r_value has a range of 0-255. All work fin as long as the value is not greater than 127. Anyone have a solution. I have a bluetooth HC-06 slave with a samsung note 10 to send via bluetooth.
A byte in java is a signed byte; Byte.MAX_VALUE = 127 Byte.MIN_VALUE = -128.
byte type holds 256 values, within the range of -128...0...127 ( -128 negative number + 127 postive number + 0 ) but unsigned byte can hold values 0 to 255.
Edit: unsigned doesn't supported in Java
Related
I have an Android App where I get Heart Rate Measurements from a Polar H10 Device.
I'm totally lost on how to interpret the heart rate. Various links to the bluetooth.com site are resulting in 404 errors unfortunately.
The characteristics value is i.e.
[16, 59, 83, 4]
From what I understood the second byte (59) is the heart rate in BPM. But this does not seem to be decimal as the value goes up to 127 and then goes on -127, -126, -125, ... It is not hex either.
I tried (in kotlin)
characteristic.value[1].toUInt()
characteristic.value[1].toInt()
characteristic.value[1].toShort()
characteristic.value[1].toULong()
characteristic.value[1].toDouble()
All values freak out as soon as the -127 appears.
Do I have to convert the 59 to binary (59=111011) and see it in there? Please give me some insight.
### Edit (12th April 2021) ###
What I do to get those values is a BluetoothDevice.connectGatt().
Then hold the GATT.
In order to get heart rate values I look for
Service 0x180d and its
characteristic 0x2a37 and its only
descriptor 0x2902.
Then I enable notifications by setting 0x01 on the descriptor. I then get ongoing events in the GattClientCallback.onCharacteristicChanged() callback. I will add a screenshot below with all data.
From what I understood the response should be 6 bytes long instead of 4, right? What am I doing wrong?
On the picture you see the characteristic on the very top. It is linked to the service 180d and the characteristic holds the value with 4 bytes on the bottom.
See Heart Rate Value in BLE for the links to the documents. As in that answer, here's the decode:
Byte 0 - Flags: 16 (0001 0000)
Bits are numbered from LSB (0) to MSB (7).
Bit 0 - Heart Rate Value Format: 0 => UINT8 beats per minute
Bit 1-2 - Sensor Contact Status: 00 => Not supported or detected
Bit 3 - Energy Expended Status: 0 => No Present
Bit 4 - RR-Interval: 1 => One or more values are present
So the first byte is a heart rate in UInt8 format, and the next two bytes are an RR interval.
To read this in Kotlin:
characteristic.getIntValue(FORMAT_UINT8, 1)
This return a heart rate of 56 bpm.
And ignore the other two bytes unless you want the RR.
It seems I found a way by retrieving the value as follows
val hearRateDecimal = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 1)
2 things are important
first - the format of UINT8 (although I don't know when to use UINT8 and when UINT16. Actually I thought I need to use UINT16 as the first byte is actually 16 (see the question above)
second - the offset parameter 1
What I now get is an Integer even beyond 127 -> 127, 128, 129, 130, ...
I am trying to collect temperature and humidity from beacons, that sends this raw data:
020106 020AFC 0A16 ABFE 70BF01 00DB00DB
where:
0x02 – length (2 bytes)
0x01 – type (flags)
0x06 – value (BIN=00000110)
0x02 -length (2 bytes)
0x0A type («Tx Power Level»)
0xFC – value (DEC =-4)
0x0A – length (10 bytes)
0x16 - type («Service Data - 16-bit UUID»
0xABFE - UUID = FEAB
0x70 – frame type (temperature and humidity)
0xBF – TX#1m
0x01 – TX power
0x00DB – temperature (DEC=219 = 21.9 C)
0x00DB – humidity (DEC – 219= 21.9C)
I am trying to build an instance, but it looks like that it is not correct, WAIDW?
m:9-10=feab, i:11-14, p:6-6, d:14-17
Thank you for your help
Try this:
"s:0-1=feab,m:2-2=70,i:3-8,p:3-3,d:5-6,d:7-8"
That expression will:
match on a 16 bit service UUID 0xFEAB (which you show)
make sure the first byte after the service UUID is 0x70 (which you show). This will ensure it is a temp and humidity frame
put the full bytes of the frame into the first identifier field accessible by beacon.getId1() (this is not very useful, but you are required to have at least one identifier field for your beacon parser)
put the raw temperature value into the first data field accessible by beacon.beacon.getDataFields().get(0)
put the raw humidity value into the second data field accessible by beacon.beacon.getDataFields().get(1)
I will explain my project :
I have my RC522 and a door connected on my Arduino UNO.
I can currently open the door with a MIFARE classic.
But now I want to open it with my Android smartphone, this is why I develop a HCE applet to accept the good APDU with the selected AID, then my phone will transfer the data in order to open the door.
But the problem is :
I don't know how to send an APDU command with my Arduino using the RC522.
Currently, for my MIFARE Cards, I use the https://github.com/miguelbalboa/rfid library.
My test code :
byte selectApdu[] = {
0x00, /* CLA */
0xA4, /* INS */
0x04, /* P1 */
0x00, /* P2 */
0x05, /* Length of AID */
0xF2, 0x22, 0x22, 0x22, 0x22,
};
byte * backData = (byte *)malloc(16*sizeof(byte));
byte * dataLen = (byte *)16;
status = mfrc522.PCD_TransceiveData(selectApdu,10,backData,dataLen,NULL,0,false);
if ( status != MFRC522::STATUS_OK) {
Serial.print(F("PCD_TransceiveData() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
else
{
Serial.println(F("PICC_TransceiveData() success "));
}
Neverless, it doesn't work ( "Timeout in communication"), and I slowly need to think that the RC522 is not compatible...
It's an (well commented) open-source project. Just have a look to source code, for instance If you use MIFARE_Read function of MFRC522.cpp
MFRC522::StatusCode MFRC522::MIFARE_Read( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from.
byte *buffer, ///< The buffer to store the data in
byte *bufferSize ///< Buffer size, at least 18 bytes. Also number of bytes returned if STATUS_OK.
) {
MFRC522::StatusCode result;
// Sanity check
if (buffer == NULL || *bufferSize < 18) {
return STATUS_NO_ROOM;
}
// Build command buffer
buffer[0] = PICC_CMD_MF_READ;
buffer[1] = blockAddr;
// Calculate CRC_A
result = PCD_CalculateCRC(buffer, 2, &buffer[2]);
if (result != STATUS_OK) {
return result;
}
// Transmit the buffer and receive the response, validate CRC_A.
return PCD_TransceiveData(buffer, 4, buffer, bufferSize, NULL, 0, true);
} // End MIFARE_Read()
You could see function PCD_TransceiveData is called and check source of this function:
/**
* Executes the Transceive command.
* CRC validation can only be done if backData and backLen are specified.
*
* #return STATUS_OK on success, STATUS_??? otherwise.
*/
MFRC522::StatusCode MFRC522::PCD_TransceiveData( byte *sendData, ///< Pointer to the data to transfer to the FIFO.
byte sendLen, ///< Number of bytes to transfer to the FIFO.
byte *backData, ///< NULL or pointer to buffer if data should be read back after executing the command.
byte *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned.
byte *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. Default NULL.
byte rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0.
bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated.
) {
byte waitIRq = 0x30; // RxIRq and IdleIRq
return PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, sendData, sendLen, backData, backLen, validBits, rxAlign, checkCRC);
} // End PCD_TransceiveData()
You could called PCD_TransceiveData or PCD_CommunicateWithPICC functions.
UPDATE
You put 0 values for parameters: "backData", "backLen", and "validBits".
validBits could be null.
backData and backLen must be defined as byte.
UPDATE2
If you have a look at library support protocols It supports ISO/IEC 14443-3 (type A) and not supports ISO/IEC 14443-4 (type B).
If you have a look at Android HCE documentation :
Specifically, Android 4.4 supports emulating cards that are based on
the NFC-Forum ISO-DEP specification (based on ISO/IEC 14443-4) and
process Application Protocol Data Units (APDUs) as defined in the
ISO/IEC 7816-4 specification. Android mandates emulating ISO-DEP only
on top of the Nfc-A (ISO/IEC 14443-3 Type A) technology. Support for
Nfc-B (ISO/IEC 14443-4 Type B) technology is optional. The layering of
all these specifications is shown in the figure 3
In this post: HCE support for ISO/IEC 14443-3 Type B?
Looking at devices in the field, some devices use Type A for HCE and
some seem to use Type B. So it's basically the device manufacturer who
decides if Type A or Type B is used. The Android API provides no means
for the app developer to influence this.
So you have to check with another Android NFC device if your device emulate ISO/IEC 14443-3 (Type A) or ISO/IEC 14443-4 (Type B). You could use NfcTagInfo application on other android device to check this.
I want to read each character from an existing wav file and assign it to a certain frequency.
I specifically want to transfer WAV files over sound from a phone to another like the "Chirp" android application.
And for that I need to map all the data to certain frequencies and play the generated tone so that the other phone can decode it and reconstitute the wav file.
Take a look at this: chirp.io/tech
For example the first line of a wave file is :
52 49 46 46 E0...
my idea is to do like:
5--> 100hz
2--> 200hz
4-->300hz
...
Is their a way to split them without changing the data?
i think i should mention that my wav file is formatted as:
static int sampleRate=44100;
static int numSample=duration*sampleRate;
long mySubChunk1Size = 16;
static short myBitsPerSample= 16;
int myFormat = 1;
static int myChannels = 1;
long myByteRate = sampleRate * myChannels * myBitsPerSample/8;
int myBlockAlign = myChannels * myBitsPerSample/8;
long myChunk2Size = generatedSnd.length* myChannels * myBitsPerSample/8;
long myChunkSize = 36 + myChunk2Size;
The way you are trying to do it is simply... naive.
I tell you why:
0x59 is a byte (decimal: 89) but you want 2 different sounds from it (0x50 and 0x09)?
It doesn't seem a good idea, since you would have 2 frequencies (for the LSB and the MSB).
Moreover, you will need to map all the 256 byte values you can have in a file,
from 0x00 to 0xFF (decimal: 255).
Plus, assigning 0x50 (decimal: 80) 100 Hz and 0x009 (decimal: 9) 200 Hz, again doesn't
make much sense to me...
Now, a possible way to do that:
I would implement an algorithm such as (byte * 32) + 440 that gives me:
440 Hz for 0x00, which is (0 * 32) + 440
...
3288 Hz for 0x59, which is (89 * 32) + 440
...
8600 Hz for 0xFF, which is (255 * 32) + 440.
All bytes will be "encoded" into frequencies in the audible spectrum.
In much a similar way to that used in the aforementioned "Chirp" method.
And I don't have to tell it that 0 is 440 Hz (nor any other association), the algorithm makes it for me.
Moreover, you can sen out (and receive) any kind of file. Not bad.
[EDIT]
Since the media (acoustic speakers/microphones) are limited to the Low Frequency range (audible sounds), you have to use audible sounds.
If you were to use Radio transmission, then you could use High Frequencies as well.
Since it really depends on construction quality. I suggested a "safe" range every speaker/microphone coupling will be able to deal with.
For reference on audible tones: http://en.wikipedia.org/wiki/Audio_frequency
i am looking at the code of a project called MyTracks:
http://code.google.com/r/jrgert-polar-bluetooth/source/browse/MyTracks/src/com/google/android/apps/mytracks/services/sensors/PolarMessageParser.java?r=ebc01faf49550bc9801633ff38bb3b8ddd6f5698
Now I am having problems with the method isValid(byte[] buffer). I don´t understand what exactly is he checking here. We want to know if the first byte in the array is the header containing 0xFE. I don´t quite understand the following lines :
boolean goodHdr = ((buffer[0] & 0xFF) == 0xFE);
boolean goodChk = ((buffer[2] & 0xFF) == (0xFF - (buffer[1] & 0xFF)));
return goodHdr && goodChk;
any ideas?
Ewoks is correct, refer to this blog post:
http://ww.telent.net/2012/5/3/listening_to_a_polar_bluetooth_hrm_in_linux
"Digging into src/com/google/android/apps/mytracks/services/sensors/PolarMessageParser.java we find a helpful comment revealing that, notwithstanding Polar's ridiculous stance on giving out development info (they don't, is the summary) the Wearlink packet format is actually quite simple.
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."
&0xff simply converts signed byte to unsigned int for doing the comparison
First line is checking is received buffer are starting with 0xFE as it should be with this Polar Wearable.
Second line is checking if length byte is correct as well because it's value by specification is 255-value writen is size byte..
This together is super simple verification that messages are correct (more complicated implementation would include CRC or other verification methods). cheers