Android Bluetooth SPP Loss/Corrupted Data - android

I'm attempting to transfer a large file (2.7MB) from a server device to an android device via bluetooth using SPP. Upon connection, the android device reads the bytes available and store into a buffer of 2.7MB. I am using the variable "counter" (counting from 0 to 127) to verify the data.
To experiment, all data is correct if the server device outputs the file byte by byte. However, if the device outputs in packets of n bytes (e.g. 128 in this case), the data received on android was corrupted without any consistent pattern - it would incorrectly read values as 0s or 1s, but it always fixed itself at the start of the packet.
Any suggestions on how to prevent loss/corruption of data is greatly appreciated.
Receiving on Android device:
int imageSize = 2718720;
int counter = 0;
int totalByte = 0;
byte[] buffer = new byte[imageSize];
while (totalByte < imageSize) {
int bytesAvailable = mInStream.available();
int numOfBytesRead = mInStream.read(buffer, totalByte, bytesAvailable);
for (int i = totalByte; i < totalByte + numOfBytesRead; i++) {
if (buffer[i] != counter) {
Log.d("BTDevice", Integer.toString(i) + ". read byte = " + Integer.toString(buffer[i] & 0xff) + " - Failed");
} else {
Log.d("BTDevice", Integer.toString(i) + ". read byte = " + Integer.toString(buffer[i] & 0xff));
}
counter++;
if (counter == 128) {
counter = 0;
}
}
totalByte += actualBytesRead;
}
Output:

Related

How do I convert a Linux C USB read to Android?

I have Tire Pressure Management System (TPMS) adapter that plugs into USB (http://store.mp3car.com/USB_TPMS_Version_2_20_4_Sensor_Kit_p/com-090.htm). I have it working with the original Windows software, as well as Linux C code to read the tire pressures and temperature. I'm now trying to use this adapter on Android and am having some difficulty. I can detect the device fine, but my reads are all returning -1 bytes read, whatever I try. Here's the C code I'm trying to convert:
int TpmsPlugin::readUsbSensor(int sid, unsigned char *buf)
{
int r, transferred;
buf[0] = 0x20 + sid;
r = libusb_interrupt_transfer(mDeviceHandle, ENDPOINT_OUT, buf, 1, &transferred, INTR_TIMEOUT);
if (r < 0) {
DebugOut() << "TPMS: USB write interrupt failed, code " << r << endl;
}
r = libusb_interrupt_transfer(mDeviceHandle, ENDPOINT_IN, buf, 4, &transferred, INTR_TIMEOUT);
if (r < 0) {
DebugOut() << "TPMS: USB read interrupt failed, code " << r << endl;
}
return r;
The value of sid is 1, 2, 3 or 4 depending on the wheel. The values are then extracted with:
lfPressure = ((float)buf[0]-40) * PRESSURE_SCALE * KPA_MULTIPLIER;
lfTemperature = (float)buf[1]-40;
You can see full implementation of this driver here as well: https://github.com/otcshare/automotive-message-broker/blob/master/plugins/tpms/tpmsplugin.cpp
My Android version is able to find the USB device, get permission to use it, connect to it, get the UsbEndpoints (it lists two), but whether bulkTransfer() or controlTransfer() I try, I've failed. In particular, I've tried a lot of different controlTransfer values based on all the docs I could find. Here is some code that I've tried:
UsbInterface intf = TpmsSectionFragment.device.getInterface(0);
UsbEndpoint endpoint_in = null, endpoint_out = null;
for (int i = 0; i < intf.getEndpointCount(); i++) {
UsbEndpoint ep = intf.getEndpoint(i);
if (ep.getDirection() == UsbConstants.USB_DIR_IN)
endpoint_in = ep;
else if (ep.getDirection() == UsbConstants.USB_DIR_OUT)
endpoint_out = ep;
}
UsbDeviceConnection connection = gUsbManager.openDevice(TpmsSectionFragment.device);
connection.claimInterface(intf, false);
int timeout = 1000;
int length = 4;
while (true) {
for (int sensorId = 1; sensorId <= 4 && mReadThreadActive; sensorId++) {
byte[] tpmsRaw = new byte[length];
tpmsRaw[0] = (byte) (0x20 + sensorId);
int out_len = connection.bulkTransfer(endpoint_out, tpmsRaw, 1, timeout);
int in_len = connection.bulkTransfer(endpoint_in, tpmsRaw, 4, timeout);
//int out_len = connection.controlTransfer(0x42, 0x0, 0x100, 0, tpmsRaw, tpmsRaw.length, timeout);
//int in_len = connection.controlTransfer(0x41, 0x0, 0x100, 0, tpmsRaw, tpmsRaw.length, timeout);
Any thoughts on what I could be doing wrong are greatly appreciated. I'm happy to try a few different things to debug further if you have any suggestions.
Thanks!
Here's the solution based on the help from Chris. I converted the calls to queue / requestWait:
ByteBuffer buf = ByteBuffer.allocate(4);
buf.put(0, (byte) (0x20 + sensorId));
UsbRequest send = new UsbRequest();
send.initialize(connection, endpoint_out);
Boolean sent = send.queue(buf, 1);
UsbRequest r1 = connection.requestWait();
send.initialize(connection, endpoint_in);
send.queue(buf, 4);
UsbRequest r2 = connection.requestWait();
The other thing I needed to tweak was this call and set the second parameter to true:
connection.claimInterface(intf, true);
That's it. Done. Thanks for the help!

How can I known whether it is a beat now of the current mp3 music in Android

I'm trying to develop such a android app: when it is druming or beating now of the current playing music, I can do something. So I should analyse the current music first, and then I should decide whether it is beating now!
I have test the Android Api Demo, using the MediaPlayer and Visualizer class I can get the original byte data, but how can I know whether it is beating now?
I'm new here...sorry if I have not describe clearly and any answer is appreciative!
Here is my partial code to refresh android view:
public void updateVisualizer(byte[] fft)
{
if(mFirst )
{
mInfoView.setText(mInfoView.getText().toString() + "\nCaptureSize: " + fft.length);
mFirst = false;
}
byte[] model = new byte[fft.length / 2 + 1];
model[0] = (byte) Math.abs(fft[0]);
for (int i = 2, j = 1; j < mSpectrumNum;)
{
model[j] = (byte) Math.hypot(fft[i], fft[i + 1]);
i += 2;
j++;
}
mBytes = model;
// I want to decide whether it is beating now
/*if(beating){
doSomeThing();
}*/
invalidate();
}

Transceive Failed on ISO15693 / Tag-it HF-I

I have some ISO15693 / Tag-it HF-I Plus chips and need to write something on them. These chips are completly fresh, and i read now a ton of pdf's telling me all the same. But nothing work, and i get all the time the Transceive Failed error.
I send these Data in the transceive command:
Byte: <data>
0: 0x00 // pdf says the tag understands only flag = 0x00
1: 0x21 // write single block
2-10: ID // needs to be send for this tag, only supports addressed mode
11: 0x00 // Block ID, try to write to block 0
12-16: DATA // LSB First
17-18: CRC16 // do i need to send this? and if yes, LSB first?
I tried very different flags and write modes but none of them work:
Flags: 0x01, 0x02, 0x20,0x22,0x42,0x40,0x80,0x82
Modes: 0x21,0xA2 (+ Vendor Mode 0x07)
this is my write function:
private void write(Tag tag) throws IOException, FormatException {
if (tag == null) {
return;
}
NfcV nfc = NfcV.get(tag);
byte[] ID = tag.getId();
nfc.connect();
Log.d(TAG, "Data: " + new String(((EmergencyApplication) getApplication()).getData()));
byte[] data = ((EmergencyApplication) getApplication()).getData();
// NfcV Tag has 64 Blocks with 4 Byte
if ((data.length / 4) > 64) {
// ERROR HERE!
Log.d(TAG, "too much data...");
}
for (int i = 0; i < data.length; i++) {
byte[] arrByte = new byte[17];
// Flags
arrByte[0] = 0x00; // Tag only supports flags = 0
// Command
arrByte[1] = 0x21;
// ID
Log.d(TAG, "Found ID length: " + ID.length + "... ID: " + Arrays.toString(ID));
System.arraycopy(ID, 0, arrByte, 2, 8);
// block number
arrByte[10] = (byte) (i);
// data
// TODO send LSB first...
System.arraycopy(data, i * 4, arrByte, 11, 4);
// CRC 16 of all command
byte[] check = new byte[15];
System.arraycopy(arrByte, 0, check, 0, 15);
int crc = CRC.crc16(check);
arrByte[15] = (byte) (crc >> 8);
arrByte[16] = (byte) (crc & 0xFF);
Log.d(TAG, "Writing Data: " + Arrays.toString(arrByte));
byte[] result = nfc.transceive(arrByte);
Log.d(TAG, "got result: " + Arrays.toString(result));
}
nfc.close();
Toast.makeText(this, "wrote to tag", Toast.LENGTH_LONG).show();
}
Is it another bug with the Nexus S? I use Cyanogenmod 10.1.2, so i think the Tag Lost Bug is fixed here... I can obviously read the tag and if i use the NFC Tag Info App, it shows me all block clear and writeable.
I have these PDFs read:
http://rfidshop.com.hk/datasheet%20tag/philip%20icode%20SLI.pdf - Datasheet of my Tag
http://www.waazaa.org/download/fcd-15693-3.pdf - ISO15693-3 datasheet
http://www.ti.com/lit/ug/scbu003a/scbu003a.pdf - Tag-it HF-I Plus datasheet
I tested Reading with the code from here: Reading a NXP ICODE SLI-L tag with Android - it works on all 64 blocks but writing still doesnt work... even with flag = 0x20...
Edit: I saw now that the DSFID on the Card is 0x00, which means for ISO15693-3 that the card is not writeable at all:
If its programming is not supported by the VICC, the VICC shall
respond with the value zero ('00')
This is the byte[] when sending 0x2B:
DSFID \ / AFI
| |
v v
infoRmation: [0, 15, 120, 40, -51, -51, 119, -128, 7, -32, 0, 0, 63, 3, -117]
Found some things out, i want to share:
Don't Send the Data with LSB first, it seems that the transceive command does this automatically on sending
Don't use addressed mode, it seems that the android implementation has some problems with that
Set the Option bit (0x40) in the Flags.
Fast Mode (0x02) seems to be supported by my tags, so you can set it or not
Don't set the CRC16, because it's added by android
But the worst thing at all is, that the Tags does not respond in the time that is compiled into the tag writer. You will get a Tag is lost. Exception but the Data will be written to the Tag! So the solution is to just ignore this exception and maybe validate the data after writing and try again if it doesnt work.
My current write code looks like this:
public static void write(Tag tag, byte[] data) throws IOException, FormatException,
InterruptedException {
if (tag == null) {
return;
}
NfcV nfc = NfcV.get(tag);
nfc.connect();
Log.d(TAG, "Max Transceive Bytes: " + nfc.getMaxTransceiveLength());
// NfcV Tag has 64 Blocks with 4 Byte
if ((data.length / 4) > 64) {
// ERROR HERE!
Log.d(TAG, "too much data...");
}
if ((data.length % 4) != 0) {
byte[] ndata = new byte[(data.length) + (4 - (data.length % 4))];
Arrays.fill(ndata, (byte) 0x00);
System.arraycopy(data, 0, ndata, 0, data.length);
data = ndata;
}
byte[] arrByte = new byte[7];
// Flags
arrByte[0] = 0x42;
// Command
arrByte[1] = 0x21;
for (int i = 0; i < (data.length / 4); i++) {
// block number
arrByte[2] = (byte) (i);
// data, DONT SEND LSB FIRST!
arrByte[3] = data[(i * 4)];
arrByte[4] = data[(i * 4) + 1];
arrByte[5] = data[(i * 4) + 2];
arrByte[6] = data[(i * 4) + 3];
Log.d(TAG, "Writing Data to block " + i + " [" + printHexString(arrByte) + "]");
try {
nfc.transceive(arrByte);
} catch (IOException e) {
if (e.getMessage().equals("Tag was lost.")) {
// continue, because of Tag bug
} else {
throw e;
}
}
}
nfc.close();
}
and it works pretty well.
If there is a real error, like the message is not understood, you will get the Transceive Failed message.

Stuttering Playback when playing a stream received via UDP socket

i want to send an audio stream from PC (C++ application, using FMOD-API to decode audio data and send via UDP Socket) to an android device. The communication already works and i can hear "sound" (100ms sound, followed by 900ms silence, alternating) on the android.
I don't know why the sound is stuttering - on the PC the same audio stream is played fine in nice quality. I think the problem is on the android..
Here is the code:
DatagramSocket sock = new DatagramSocket(12345);
byte []bSockBuffer = new byte[1024];
byte []bRecvBufTmp;
int iAudioBufSize, iCurAudioBufPos = 0;
sock.setReceiveBufferSize(bSockBuffer.length);
// Audio Stream initialisieren:
iAudioBufSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, iAudioBufSize, AudioTrack.MODE_STREAM);
track.play();
while (true)
{
DatagramPacket pack = new DatagramPacket(bSockBuffer, bSockBuffer.length);
// Paket empfangen:
sock.receive(pack);
track.write(pack.getData(), 0, pack.getLength());
}
I'm sure to set up 'AudioTrack' object correctly, settings compare to my settings in the c++ application.
An other step was pre-buffering the received socket-data in a temporary 'byte[]' variable and writing it to the AudioTrack-object when the size of the buffer 'iAudioBufSize' was reached.
This did not helped.
Any idears?
Thanks
[EDIT]
Code of C++ Application, used sample "manualdecode" of FMOD API examples:
FMOD_RESULT F_CALLBACK pcmreadcallback(FMOD_SOUND *sound, void *data, unsigned int datalen)
{
CCtrlSocket *cClientTmp = /* Obtaining target client sock here */;
FMOD_RESULT result;
unsigned int read, uSentTmp, uSizeTmp;
EnterCriticalSection(&decodecrit);
if (!decodesound)
return (FMOD_ERR_FILE_EOF);
result = decodesound->readData(data, datalen, &read);
if (result == FMOD_ERR_FILE_EOF)
{
// Handle looping:
decodesound->seekData(0);
datalen -= read;
result = decodesound->readData((char*) data + read, datalen, &read);
}
// Split package in multiple parts:
uSentTmp = 0;
do
{
uSizeTmp = (read - uSentTmp);
if (uSizeTmp > 1024)
uSizeTmp = 1024;
uSentTmp += cClientTmp->SendAudioData((char*) data + uSentTmp, uSizeTmp);
} while (uSentTmp < read);
LeaveCriticalSection(&decodecrit);
return (FMOD_OK);
}
I've done this problem.
The mess was an entry in a logfile that has cost lots of time creating a lag :(
Now i can hear the streamed music on my android client. But there are still some lags. I've experimented a LOT of values for socket and AudioTrack buffers.
I have compared the amount of sent and received bytes: In 20 secs sending 9170000 bytes of data results in receiving 8120000 bytes on android device. At first the stream is played fast for 3 secs (that means buffer's full?). After 30 secs the stream lags (which means buffer's empty?).
In general the music quality is very good, but there is a sizzling noise all the time (which indicates lost socket packages?).
My 'PlaybackStart()' function has changed - i'm not using a PCM read callback anymore:
FMOD_RESULT CAudioStream::PlaybackStart()
{
CCtrlSocket *cClientTmp;
unsigned int read, uSentTmp, uSizeTmp;
FMOD_RESULT result;
result = system->createStream("C:\\test.mp3", FMOD_OPENONLY | FMOD_ACCURATETIME, 0, &sound);
if(result != FMOD_OK)
return (result);
int iChannels, iBits;
FMOD_SOUND_FORMAT fFormat;
FMOD_SOUND_TYPE fType;
result = sound->getFormat(&fType, &fFormat, &iChannels, &iBits);
if(result != FMOD_OK)
return (result);
void *data;
unsigned int length = 0;
int iSampleSec = 1; // Playtime
int iSampleSize = (44100 * 2 * sizeof(signed short) * iSampleSec);
int iSleep = 6; // Sleep after sending a package
DWORD dSleepTotal;
result = sound->getLength(&length, FMOD_TIMEUNIT_PCMBYTES);
if(result != FMOD_OK)
return (result);
data = malloc(iSampleSize);
if (!data)
return (FMOD_RESULT_FORCEINT);
cClientTmp = (CCtrlSocket*) CCtrlSocket::cServerSock.GetClientSock(CCtrlSocket::cServerSock.GetClientSockCount() - 1);
do
{
result = sound->readData((char*) data, iSampleSize, &read);
if ((result != FMOD_OK) && (result != FMOD_ERR_FILE_EOF))
ASSERT(FALSE);
else if (read > 0)
{
dSleepTotal = 0;
for (int i = 0; i < read; i += NET_SVR_AUDIO_BUFFER)
{
// MIN_VAL_LIMITED ((MIN_VAL(VAL1, VAL2) <= LIMIT) ? LIMIT : MIN_VAL(VAL1, VAL2))
cClientTmp->SendAudioData((char*) data + i, MIN_VAL_LIMITED(NET_SVR_AUDIO_BUFFER, (read - i), 0));
// Sleep after sending every package:
Sleep(iSleep);
dSleepTotal += iSleep;
}
if (dSleepTotal < (iSampleSec * 1000))
{
dSleepTotal = (iSampleSec * 1000) - dSleepTotal;
// Sleep after sending every second playtime:
Sleep(dSleepTotal);
}
}
} while (read > 0);
result = sound->release();
if(result != FMOD_OK)
return (result);
result = system->close();
if(result != FMOD_OK)
return (result);
result = system->release();
if(result != FMOD_OK)
return (result);
return (result);
}
I have experimented with different sleep-timings, too.

Why does SKIA not use a custom FilterInputStream?

I'm trying to decode a bitmap from an extended FilterInputStream. I have to perform on-the-fly byte manipulation to the image data to provide a decodable image to SKIA, however it seems like SKIA ignores my custom InputStream and initializes one of its own...
When I run my test application, attempting to load in a 2mb large JPEG results in ObfuscatedInputStream.read([]) being called only once from BitmapFactory.decodeStream()
It seems like once the type of file is determined from the first 16kb of data retrieved from my ObfuscatedInputStream it initializes its own native stream and reads from that, effectively rendering all changes I make to how the input stream should work useless...
Here is the buffered read function in my extended FilterInputStream class. The Log.d at the top of the function is only executed once.
#Override
public int read(byte b[], int off, int len) throws IOException
{
Log.d(TAG, "called read[] with aval + " + super.available() + " len " + len);
int numBytesRead = -1;
if (pos == 0)
{
numBytesRead = fill(b);
if (numBytesRead < len)
{
int j;
numBytesRead += ((j = super.read(b, numBytesRead, len - numBytesRead)) == -1) ? 0 : j ;
}
}
else
numBytesRead = super.read(b, 0, len);
if (numBytesRead > -1)
pos += numBytesRead;
Log.d(TAG, "actually read " + numBytesRead);
return numBytesRead;
}
Has anyone ever encountered this issue? It seems like the only way to get my desired behavior is to rewrite portions of the SKIA library... I would really like to know what the point of the InputStream parameter is if the native implementation initializes a stream of its own...
turns out that it wasnt able to detect that it was an actual image from the first 1024 bytes it takes in. If it doesnt detect that the file is an actual image, it will not bother decoding the rest, hence only having read[] called once.

Categories

Resources