Random gaps while recording data on Android smartwatch - android

I'm using a Fossil Gen 5 smartwatch running WearOS to record sensor data from Accelerometer, Gyroscope (32 Hz) and PPG sensor (64 Hz). I'm using a unique bufferedWriter object for each sensor to write data to a .txt file as each sensor event is created (shown below):
void registerSensor(){
Log.i(TAG,"Sensor Registered");
try {
accWriter = new BufferedWriter(new FileWriter(accFile, true));
gyrWriter = new BufferedWriter(new FileWriter(gyrFile, true));
ppgWriter = new BufferedWriter(new FileWriter(ppgFile, true));
} catch (IOException e) {
e.printStackTrace();
}
//just in case
if (sensorManager == null)
sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
listener = new SensorEventListener() {
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
#Override
public void onSensorChanged(SensorEvent event) {
switch (event.sensor.getType()) {
case 65572:
String msg1 = "Recording PPG";
mData1.setText(msg1);
ppgTime = System.currentTimeMillis() + (event.timestamp - SystemClock.elapsedRealtimeNanos()) / 1000000L;
try {
ppgWriter.write(ppgTime + ", " + event.values[0] + ", " + ambient + "\n");
} catch (IOException e) {
e.printStackTrace();
}
break;
case Sensor.TYPE_ACCELEROMETER:
String msg2 = "Recording ACC";
mData2.setText(msg2);
accTime = System.currentTimeMillis() + (event.timestamp - SystemClock.elapsedRealtimeNanos()) / 1000000L;
try {
accWriter.write(accTime + ", " + df.format(event.values[0]) + ", " + df.format(event.values[1]) + ", " + df.format(event.values[2]) + ", " + ambient + "\n");
} catch (IOException e) {
e.printStackTrace();
}
break;
case Sensor.TYPE_GYROSCOPE:
String msg3 = "Recording GYR";
mData3.setText(msg3);
gyrTime = System.currentTimeMillis() + (event.timestamp - SystemClock.elapsedRealtimeNanos()) / 1000000L;
try {
gyrWriter.write(gyrTime + ", " + df.format(event.values[0]) + ", " + df.format(event.values[1]) + ", " + df.format(event.values[2]) + ", " + ambient + "\n");
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
};
sensorManager.registerListener(listener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),31250); // SensorManager.SENSOR_DELAY_FASTEST);
sensorManager.registerListener(listener, sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), 31250);
sensorManager.registerListener(listener, sensorManager.getDefaultSensor(65572), 15625);
}
I expect the sampling frequency to hover around the intended value. But I'm getting random missing data chunks of ~ 60 s in all 3 sensor streams.
Please see this image that visually describes the issue (I'm not able to embed images yet)
I've tested this a number of times, with the same result. I thought some events might be dropped, so I tried writing all the data to a String and then writing the String to a file after a certain size is exceeded. This didn't solve the issue.
Any help or suggestions are greatly appreciated! Excuse my etiquette as I'm new to StackOverflow.

If the samples are being dropped when the screen is off you need to use wakeup sensors.
You can do that by passing true to sensorManager.registerListener.
And according to the doc, the sampling frequency is only a hint to the os.

Related

How to read for data from CDC device connected to Android using usb-serial-for-android?

I'm using this library to send and receive data from a Feather 32u4 device. The Feather sends some canned data when the port is opened, and then echos back what is sent to it.
I'm having issues understanding how the read and write methods work in the library. I'm pretty sure I'm using write correctly, but I don't know about read. The returned length when read is used is always 0, and I am using the correct baudrate. I'm just not totally sure how it should be used. I'm still trying to figure out the event driven option also.
private void DoTheThing () {
String textMessage = "";
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
// Find available drivers for Feather board.
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x239a, 0x800c, CdcAcmSerialDriver.class);
UsbSerialProber prober = new UsbSerialProber(customTable);
List<UsbSerialDriver> drivers = prober.findAllDrivers(manager);
if (drivers.isEmpty()) {
textMessage += "Could not find any drivers.\n";
m_textView.setText(textMessage);
return;
}
textMessage += "Driver found\n";
m_textView.setText(textMessage);
UsbDeviceConnection connection = null;
UsbSerialDriver driver = drivers.get(0);
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(INTENT_ACTION_GRANT_USB), 0);
manager.requestPermission(driver.getDevice(), usbPermissionIntent);
try {
connection = manager.openDevice(driver.getDevice());
} catch (Exception e) {
textMessage += e + "\n";
m_textView.setText(textMessage);
}
if (connection == null) {
// add UsbManager.requestPermission(driver.getDevice(), ..) handling here
textMessage += "Could not open device.\n";
m_textView.setText(textMessage);
return;
}
textMessage += "Device opened\n";
m_textView.setText(textMessage);
UsbSerialPort port = driver.getPorts().get(0);
// Most devices have just one port (port 0)
try {
port.open(connection);
port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
} catch (IOException e) {
textMessage += e + "\n";
m_textView.setText(textMessage);
return;
}
textMessage += "Connection established\n";
m_textView.setText(textMessage);
// Get received data on connection.
int length = -2;
byte[] receivedData = new byte[64];
try {
length = port.read(receivedData, 2000);
} catch (Exception e) {
textMessage += "Oops: " + e + "\n";
m_textView.setText(textMessage);
}
String data = new String(receivedData);
textMessage += "Data recieved: " + length + " " + data + "\n";
m_textView.setText(textMessage);
// Send canned data.
length = -2;
try {
length = port.write("a".getBytes(), 2000);
} catch (Exception e) {
textMessage += "Oops: " + e + "\n";
m_textView.setText(textMessage);
}
textMessage += "Data sent " + length + "\n";
m_textView.setText(textMessage);
// Get received data.
length = -2;
receivedData = new byte[64];
try {
length = port.read(receivedData, 2000);
} catch (Exception e) {
textMessage += "Oops: " + e + "\n";
m_textView.setText(textMessage);
}
data = new String(receivedData);
textMessage += "Data recieved: " + length + " " + data;
m_textView.setText(textMessage);
}
EDIT
Getting a hard crash when I set the DTR flag to true on my port.
m_port = driver.getPorts().get(0);
// Most devices have just one port (port 0)
try {
m_port.setDTR(true); // <-- hard crash
m_port.open(connection);
m_port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
} catch (IOException e) {
m_textMessage += e + "\n";
m_textView.setText(m_textMessage);
return;
}
Could m_port still be uninitialized when it gets to that point?
Derp.
length is 0 when nothing is received within the 2000 msec timeout.
For CDC devices like the 32u4 you typically have to set DTR line as mentioned here

Gravity sensor listener not working

I want to get accelerometer sensor data which is in earth axis through a service. I read about a way to do it as well on one of the posts on stackoverflow. But I have an issue.
#Override
public void onSensorChanged(SensorEvent event) {
Toast.makeText(this, "Hollyy shiiitt",Toast.LENGTH_SHORT);
String acceldata = "";
float[] gravityValues = null;
float[] magneticValues = null;
if (event.sensor.getType() == Sensor.TYPE_GRAVITY) {
gravityValues = event.values.clone();
Toast.makeText(this, "The gra data is " + String.valueOf(gravityValues), Toast.LENGTH_SHORT);
}
if ((gravityValues != null) && (magneticValues != null)
&& (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)) {
// float for use in conversion device relative acceleration to earth axis acceleration
float[] deviceRelativeAcceleration = new float[4];
deviceRelativeAcceleration[0] = event.values[0];
deviceRelativeAcceleration[1] = event.values[1];
deviceRelativeAcceleration[2] = event.values[2];
deviceRelativeAcceleration[3] = 0;
// Change the device relative acceleration values to earth relative values
// X axis -> East
// Y axis -> North Pole
// Z axis -> Sky
float[] R = new float[16], I = new float[16], earthAcc = new float[16];
SensorManager.getRotationMatrix(R, I, gravityValues, magneticValues);
float[] inv = new float[16];
android.opengl.Matrix.invertM(inv, 0, R, 0);
android.opengl.Matrix.multiplyMV(earthAcc, 0, inv, 0, deviceRelativeAcceleration, 0);
acceldata = String.valueOf(lat) + "," + String.valueOf(lon) + "," + String.valueOf(speed)+","+ String.valueOf(earthAcc[0]) + "," + String.valueOf(earthAcc[1]) + "," + String.valueOf(earthAcc[2])+ "," + String.valueOf(event.values[0])+ "," + String.valueOf(event.values[1])+ "," + String.valueOf(event.values[2]);
}
//SDK version check
if(Build.VERSION.SDK_INT > 18) {
File file;
FileWriter filew; // Internal Storage writing
try {
file = new File(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) + "/" + filename); //Android 4.4 and above
filew = new FileWriter(file, true); //true for append
filew.write(acceldata + String.valueOf(gravityValues) + String.valueOf(magneticValues) + "\n");
filew.close();
} catch (Exception e) {
e.printStackTrace();
}
}
else{
String data = acceldata + "\n" ;
try {
FileOutputStream fOut = openFileOutput("/" + filename,Context.MODE_APPEND);
fOut.write(data.getBytes());
fOut.close();
Toast.makeText(getBaseContext(),"file saved",Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getBaseContext(),"file not saved API < 19",Toast.LENGTH_SHORT).show();
}
}
}
The if statement for gravity sensor on location changed doesn't return any value so the next statement also doesn't work as gravityValues has a null value.
The sensors registered are
mAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mMagnetsensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mGravity = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
They are then registered as
int SamplingFrequency = 2 * 100000; // delay in microsecond. in this case 0.2 second
sensorManager.registerListener(this, mAccelerometer,SamplingFrequency);
sensorManager.registerListener(this, mMagnetsensor, SamplingFrequency);
sensorManager.registerListener(this,mGravity,SamplingFrequency);
I am a newbie in app development so any help would be appreciated.
Your device probably does not have gravity sensor. Check if it's available
if (mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) {
Toast.makeText(ActivitySensor1Availability.this, "Gravity AVAILABLE", Toast.LENGTH_SHORT).show();
} else {
// Failure! No Gravity Sensor.
Toast.makeText(ActivitySensor1Availability.this, "Failure! No Gravity Sensor", Toast.LENGTH_SHORT).show();
}

onSimulatorDataUpdated() not getting called

private void initFlightController() {
DJIAircraft aircraft = DJISimulatorApplication.getAircraftInstance();
if (aircraft == null || !aircraft.isConnected()) {
log("initFlightController: aircraft not connected");
showToast("Disconnected");
mFlightController = null;
return;
} else {
log("initFlightController: aircraft CONNECTED");
mFlightController = aircraft.getFlightController();
DJISimulator djiSimulator = mFlightController.getSimulator();
log("initFlightController: djiSimulator has started : "+djiSimulator.hasSimulatorStarted());
djiSimulator.setUpdatedSimulatorStateDataCallback(new DJISimulator.UpdatedSimulatorStateDataCallback() {
#Override
public void onSimulatorDataUpdated(final DJISimulatorStateData djiSimulatorStateData) {
log("onSimulatorDataUpdated: ");
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
String yaw = String.format("%.2f", djiSimulatorStateData.getYaw());
String pitch = String.format("%.2f", djiSimulatorStateData.getPitch());
String roll = String.format("%.2f", djiSimulatorStateData.getRoll());
String positionX = String.format("%.2f", djiSimulatorStateData.getPositionX());
String positionY = String.format("%.2f", djiSimulatorStateData.getPositionY());
String positionZ = String.format("%.2f", djiSimulatorStateData.getPositionZ());
mTextView.setText("Yaw : " + yaw + ", Pitch : " + pitch + ", Roll : " + roll + "\n" + ", PosX : " + positionX +
", PosY : " + positionY +
", PosZ : " + positionZ);
}
});
}
});
}
}
I am testing the sample code given for android in Dji-Developer. Every thing goes fine but the onSimulatorDataUpdated() doesnt get called.
it even prints the log
"initFlightController: djiSimulator has started : true"
I found the solution for the problem. The code doesn't have any problem, the RC has a button at the left front area which has to be set to P mode.

SPP Android BT Connection quits after seconds (EEG readings)

I have created an app that receives data from a bt transmitter (Bluegiga). The readings are from EEG signals. The data rate is 1Khz (I have to admit it's high). Anyway, I acquire some data for some seconds and then the Bluetooth acts like there is no incoming data (which is not true). If I try to disconnect the Bluetooth using the app is clear that there is no more communication with the bt module at the EEG board since it doesn't respond to the desconnection (It has a led that indicates when is connected, and it doesn't turn of/on or anything).
If I decrease the data rate to (let's say 500hz) the app works ok, with some occasional 'quits', but tolerable. If I decrease it more the app works with no problems.
Of curse, by design, my app must work at 1Khz data rate so here is where the problem comes.
I have check some other post, trying to hit some kind of sns but nothing match my problem exactly (anyway I have tried to use the information on them but with no success obviously).
Sometimes I get this message, "dm_pm_timer expires", sometimes no (after the bt stops working).
Sadly there is no indication, Exception or message that can tell me what's going on.
Here is my Code for the BT reception Thread
class BluetoothReadThread extends Thread {
private final InputStream iStream;
private final OutputStream mmOutputStream;
private boolean continueReading = true;
public BluetoothReadThread() {
InputStream tmp = null;
OutputStream tmp2 = null;
try {
tmp = btSocket.getInputStream();
tmp2 = btSocket.getOutputStream();
} catch (IOException e) {
}
iStream = tmp;
mmOutputStream = tmp2;
}
#Override
public void run() {
int c;
int waitCount = 0;
while (continueReading) {
try {
if (iStream.available() > 0) {
waitCount = 0;
c = iStream.read();
readBuffer[readBufferPosition++] = c;
if (readBufferPosition == bitsExpected) {
if (bitsExpected == 22) {
ch1 = MultiplicationCombine(readBuffer[4], readBuffer[3]);
ch2 = MultiplicationCombine(readBuffer[6], readBuffer[5]);
ch3 = MultiplicationCombine(readBuffer[8], readBuffer[7]);
ch4 = MultiplicationCombine(readBuffer[10], readBuffer[9]);
ch5 = MultiplicationCombine(readBuffer[12], readBuffer[11]);
ch6 = MultiplicationCombine(readBuffer[14], readBuffer[13]);
ch7 = MultiplicationCombine(readBuffer[16], readBuffer[15]);
ch8 = MultiplicationCombine(readBuffer[18], readBuffer[17]);
} else {
ch1 = (int) filter_3((double)MultiplicationCombine(readBuffer[5], readBuffer[4], readBuffer[3]));
ch2 = (int) filter_4((double)MultiplicationCombine(readBuffer[8], readBuffer[7], readBuffer[6]));
ch3 = (int) filter_2((double)MultiplicationCombine(readBuffer[11], readBuffer[10], readBuffer[9]));
ch4 = (int) filter_2((double)MultiplicationCombine(readBuffer[14], readBuffer[13], readBuffer[12]));
ch5 = (int) filter_2((double)MultiplicationCombine(readBuffer[17], readBuffer[16], readBuffer[15]));
ch6 = (int) filter_2((double)MultiplicationCombine(readBuffer[20], readBuffer[19], readBuffer[18]));
ch7 = (int) filter_2((double)MultiplicationCombine(readBuffer[23], readBuffer[22], readBuffer[21]));
ch8 = (int) filter_2((double)MultiplicationCombine(readBuffer[26], readBuffer[25], readBuffer[24]));
}
Header_int = readBuffer[0];
PK_ID_int = readBuffer[1];
PK_Counter_int = readBuffer[2];
if (downsample++ == downsample_value) {
addEntry(ch1 / scaCh1, ch2 / scaCh2, ch3 / scaCh3, ch4 / scaCh4, ch5 / scaCh5, ch6 / scaCh6, ch7 / scaCh7, ch8 / scaCh8);
downsample = 0;
}
//ProgrNum,PacketType,Ch1,Ch2,Ch3,Ch4,Ch5,Ch6,Ch7,Ch8,MRK
if (write_open) {
osw.write(PK_Counter_int + "," + PK_ID_int + "," + ch1 + "," + ch2 + "," + ch3 + "," + ch4 + "," + ch5 + "," + ch6 + "," + ch7 + "," + ch8 + "," + bolOpenClose + "\n");
//osw.write(PK_Counter_int + "," + PK_ID_int + "," + ch1 + "," + ch2 + "," + ch3 + "," + ch4 + "," + ch5 + "," + ch6 + "," + ch7 + "," + ch8 + "," + "\n");
}
System.out.println(PK_Counter_int + "," + PK_ID_int + "," + ch1 + "," + ch2 + "," + ch3 + "," + ch4 + "," + ch5 + "," + ch6 + "," + ch7 + "," + ch8 + ", AV=" + iStream.available() );
mmOutputStream.write(valueSTR.getBytes());
// if(downsample++==14) { safe_copy(readBuffer); plot=true; downsample=0;}
readBufferPosition = 0;
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
System.out.println(e + "\nError sending data + :" + e);
// Bluetooth error! Stop reading.
//this.stopAndSendIntent();
}
}
}
/*
public void stopAndSendIntent() {
this.cancel();
Intent intent = new Intent();
intent.setAction(BLUETOOTH_ACTION_DONE_READING);
sendBroadcast(intent);
}
*/
public void cancel() {
System.out.println("-----Cancelling readThread!!");
try {
iStream.close();
} catch (IOException e) {
} catch (NullPointerException e) {
}
;
continueReading = false;
}
}
It works like this:
I read a received character (c=iStream.read()).
Then I copy this character to an int array until I reach the length of the packet (it can be 22 or 28 (bitsExpected)).
The following part is just filtering and plotting of the signal.
I have tried many other implementations but I get the same result.
Even if I eliminate the part of the filtering and plotting (just reading data) the problem persists.
If instead of working with array, I work with string, i.e, using append() (which should be the same?) I manage to get an working connection (no quits) but, as soon as I manipulate the program using the array everything is the same.
I'm stuck with this for 1 month already, so I will really appreciate any comments, past experience or suggestions.
Thanks in advance.
I just added this piece of code
if (PK_Counter_int % 100 == 0) mmOutputStream.write(startTring.getBytes());
and it works just fine so far.

how to get call time duration in android ? and also multiple time write data in file?

public void onCallStateChanged(int state,String incomingNumber)
{
System.out.print("\nState :- "+state);
switch(state){
case TelephonyManager.CALL_STATE_IDLE:
if(flag==true && ringflag == true)
{
flag=false;
ringflag=false;
System.out.print("\nflag = " + flag);
System.out.print("\nringflag = " + ringflag);
stop = System.currentTimeMillis();
System.out.println("\nTotal time : " +stop);
System.out.println("\nTotal time : " +(stop - start)/1000);
System.out.println("\nIDLE : " + incomingNumber);
long time = (stop - start) / 1000;
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
f = new File(path + "/sms.txt");
if (f.exists()) {
try {
raf =new RandomAccessFile(f, "rw");
long pointer = raf.length();
raf.seek(pointer);
String data = ":-"+no+","+time;
raf.writeBytes(data);
raf.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
raf = new RandomAccessFile(f,"rw");
String data = ":-"+no+","+time;
raf.writeBytes(data);
raf.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if(ringflag == true)
{
System.out.println("OFFHOOK :- " + incomingNumber);
start = System.currentTimeMillis();
System.out.print("\nStart is :-" + start);
flag=true;
}
break;
case TelephonyManager.CALL_STATE_RINGING:
no = incomingNumber;
System.out.println("Ringing : " + incomingNumber);
ringflag= true;
break;
}
}
I can answer the first part of your question
To get the call duration it is important to access the Call Logs.
Using the information given in CallLog.Calls, It can be done like below:
Uri allCalls = Uri.parse("content://call_log/calls");
Cursor c = managedQuery(allCalls, null, null, null, null);
for(String colName : c.getColumnNames())
Log.v(TAG, "Column Name: " + colName);
if (c.moveToFirst())
{
do{
String id = c.getString(c.getColumnIndex(CallLog.Calls._ID));
String num = c.getString(c.getColumnIndex(CallLog.Calls.NUMBER));
int type = Integer.parseInt(c.getString(c.getColumnIndex(CallLog.Calls.TYPE)));
String duration = c.getString(c.getColumnIndex(CallLog.Calls.DURATION));
System.out.println("call time duration is"+duration);
switch (type)
{
case 1: Log.v(TAG, id + ", " +num + ": INCOMING") ; break;
case 2: Log.v(TAG, id + ", " +num + ": OUTGOING") ;break;
case 3: Log.v(TAG, id + ", " +num + ": MISSED") ; break;
}
} while (c.moveToNext());
}
Refer this nice blog post for more information.

Categories

Resources