diff --git a/app/src/main/java/io/pslab/communication/sensors/VL53L0X.java b/app/src/main/java/io/pslab/communication/sensors/VL53L0X.java index 166c6157d..bf3ec35ff 100644 --- a/app/src/main/java/io/pslab/communication/sensors/VL53L0X.java +++ b/app/src/main/java/io/pslab/communication/sensors/VL53L0X.java @@ -276,7 +276,7 @@ private void performSingleRefCalibration(int vhvInitByte) throws Exception { i2c.write(ADDRESS, new int[]{0x00}, SYSRANGE_START); } - public int getRaw() throws Exception { + public int getRaw() throws IOException { for (int[] regValPair : new int[][]{ {0x80, 0x01}, {0xFF, 0x01}, diff --git a/app/src/main/java/io/pslab/sensors/AbstractSensorActivity.java b/app/src/main/java/io/pslab/sensors/AbstractSensorActivity.java new file mode 100644 index 000000000..7b1928366 --- /dev/null +++ b/app/src/main/java/io/pslab/sensors/AbstractSensorActivity.java @@ -0,0 +1,281 @@ +package io.pslab.sensors; + +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.text.Editable; +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.RelativeLayout; +import android.widget.SeekBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +import java.util.Locale; + +import io.pslab.R; +import io.pslab.communication.ScienceLab; +import io.pslab.others.ScienceLabCommon; + +abstract class AbstractSensorActivity extends AppCompatActivity { + private static final String TAG = AbstractSensorActivity.class.getSimpleName(); + + private static final String KEY_PLAY = TAG + "_play"; + private static final String KEY_RUN_INDEFINITELY = TAG + "_run_indefinitely"; + private static final String KEY_TIME_GAP = TAG + "_time_gap"; + private static final String KEY_FLAG = TAG + "_flag"; + private static final String KEY_START_TIME = TAG + "_start_time"; + private static final String KEY_COUNTER = TAG + "_counter"; + + private int counter; + private ScienceLab scienceLab; + private long startTime; + private int flag; + private boolean play = false; + private boolean runIndefinitely = true; + private int timeGap = 100; + + private RelativeLayout sensorDock; + private SeekBar timeGapSeekbar; + private TextView timeGapLabel; + private CheckBox indefiniteSamplesCheckBox; + private EditText samplesEditBox; + private ImageButton playPauseButton; + + private HandlerThread handlerThread; + private Handler handler; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getLayoutResId()); + + if (savedInstanceState != null) { + play = savedInstanceState.getBoolean(KEY_PLAY); + runIndefinitely = savedInstanceState.getBoolean(KEY_RUN_INDEFINITELY); + timeGap = savedInstanceState.getInt(KEY_TIME_GAP); + flag = savedInstanceState.getInt(KEY_FLAG); + startTime = savedInstanceState.getLong(KEY_START_TIME); + counter = savedInstanceState.getInt(KEY_COUNTER); + } + + sensorDock = findViewById(R.id.sensor_control_dock_layout); + indefiniteSamplesCheckBox = sensorDock.findViewById(R.id.checkBox_samples_sensor); + timeGapSeekbar = sensorDock.findViewById(R.id.seekBar_timegap_sensor); + timeGapLabel = sensorDock.findViewById(R.id.tv_timegap_label); + samplesEditBox = sensorDock.findViewById(R.id.editBox_samples_sensors); + playPauseButton = sensorDock.findViewById(R.id.imageButton_play_pause_sensor); + + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + final ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setTitle(getTitleResId()); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowHomeEnabled(true); + } + + setSensorDock(); + sensorDock.setVisibility(View.VISIBLE); + + scienceLab = ScienceLabCommon.scienceLab; + + handlerThread = new HandlerThread("MyHandlerThread"); + handlerThread.start(); + Looper looper = handlerThread.getLooper(); + handler = new Handler(looper); + + if (play) { + startTimerTask(); + } + } + + @Override + protected void onDestroy() { + play = false; + handlerThread.quit(); + super.onDestroy(); + } + + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putBoolean(KEY_PLAY, play); + outState.putBoolean(KEY_RUN_INDEFINITELY, runIndefinitely); + outState.putInt(KEY_TIME_GAP, timeGap); + outState.putInt(KEY_FLAG, flag); + outState.putLong(KEY_START_TIME, startTime); + } + + @NonNull + private Runnable getTimerTask() { + + return () -> { + if (play && scienceLab.isConnected() && shouldPlay()) { + if (flag == 0) { + startTime = System.currentTimeMillis(); + flag = 1; + } + SensorDataFetch sensorDataFetch = getSensorDataFetch(); + if (sensorDataFetch == null) { + Log.w(TAG, "No SensorDataFetch!"); + } else { + sensorDataFetch.execute(); + } + if (play) { + startTimerTask(); + } + } else { + setPlayButton(false); + } + }; + } + + private void startTimerTask() { + handler.postDelayed(getTimerTask(), timeGap); + } + + protected ScienceLab getScienceLab() { + return scienceLab; + } + + private void setSensorDock() { + final int step = 1; + final int max = 1000; + final int min = 100; + + playPauseButton.setOnClickListener(v -> { + if (play && scienceLab.isConnected()) { + play = false; + } else if (!scienceLab.isConnected()) { + play = false; + } else { + play = true; + startTimerTask(); + if (!indefiniteSamplesCheckBox.isChecked()) { + Editable text = samplesEditBox.getText(); + counter = text.length() == 0 ? 0 : Integer.parseInt(text.toString()); + } + } + setPlayButton(play); + }); + + setPlayButton(play); + + sensorDock.setVisibility(View.VISIBLE); + + indefiniteSamplesCheckBox.setChecked(runIndefinitely); + samplesEditBox.setEnabled(!runIndefinitely); + samplesEditBox.setText(String.valueOf(counter)); + indefiniteSamplesCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + runIndefinitely = true; + samplesEditBox.setEnabled(false); + } else { + runIndefinitely = false; + samplesEditBox.setEnabled(true); + } + }); + + timeGapSeekbar.setMax((max - min) / step); + timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + timeGap = min + (progress * step); + timeGapLabel.setText( + String.format( + Locale.getDefault(), + "%d%s", timeGap, getString(R.string.unit_milliseconds) + ) + ); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // nothing to do here + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // nothing to do here + } + }); + } + + private void setPlayButton(boolean isPlaying) { + playPauseButton.setImageResource(isPlaying ? R.drawable.circle_pause_button : R.drawable.circle_play_button); + } + + protected boolean shouldPlay() { + if (play) { + if (indefiniteSamplesCheckBox.isChecked()) + return true; + else if (counter > 0) { + counter--; + return true; + } else { + play = false; + return false; + } + } else { + return false; + } + } + + /** + * Get time of first start of sensor data capture. + * + * @return time in ms + */ + protected long getStartTime() { + return startTime; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + } + return true; + } + + protected abstract SensorDataFetch getSensorDataFetch(); + + protected abstract int getLayoutResId(); + + protected abstract int getTitleResId(); + + protected abstract class SensorDataFetch { + + private volatile boolean isSensorDataAcquired; + + protected float getTimeElapsed() { + return (System.currentTimeMillis() - getStartTime()) / 1000f; + } + + protected boolean isSensorDataAcquired() { + return isSensorDataAcquired; + } + + protected void execute() { + getSensorData(); + isSensorDataAcquired = true; + updateUi(); + } + + abstract void getSensorData(); + + abstract void updateUi(); + } +} diff --git a/app/src/main/java/io/pslab/sensors/SensorADS1115.java b/app/src/main/java/io/pslab/sensors/SensorADS1115.java index 5be642de0..047546fc5 100644 --- a/app/src/main/java/io/pslab/sensors/SensorADS1115.java +++ b/app/src/main/java/io/pslab/sensors/SensorADS1115.java @@ -1,22 +1,13 @@ package io.pslab.sensors; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; -import android.view.MenuItem; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.RelativeLayout; -import android.widget.SeekBar; +import android.util.Log; import android.widget.Spinner; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.Legend; @@ -30,93 +21,35 @@ import java.util.ArrayList; import io.pslab.R; -import io.pslab.communication.ScienceLab; import io.pslab.communication.peripherals.I2C; import io.pslab.communication.sensors.ADS1115; -import io.pslab.others.ScienceLabCommon; -public class SensorADS1115 extends AppCompatActivity { - private static int counter; - private final Object lock = new Object(); - private ScienceLab scienceLab; - private SensorADS1115.SensorDataFetch sensorDataFetch; - private TextView tvSensorADS1115; - private LineChart mChart; - private long startTime; - private int flag; - private ArrayList entries; - private RelativeLayout sensorDock; - private CheckBox indefiniteSamplesCheckBox; - private EditText samplesEditBox; - private SeekBar timeGapSeekbar; - private TextView timeGapLabel; - private ImageButton playPauseButton; - private boolean play; - private boolean runIndefinitely; - private int timeGap; +public class SensorADS1115 extends AbstractSensorActivity { + private static final String TAG = SensorADS1115.class.getSimpleName(); + private static final String KEY_ENTRIES = TAG + "_entries"; + private static final String KEY_VALUE = TAG + "_value"; + + private SensorDataFetch sensorDataFetch; private ADS1115 sensorADS1115; + private ArrayList entries; + + private LineChart mChart; + private TextView tvSensorADS1115; + @Override - protected void onCreate(Bundle savedInstanceState) { + protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sensor_ads1115); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.ads1115); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } - sensorDock = findViewById(R.id.sensor_control_dock_layout); - indefiniteSamplesCheckBox = findViewById(R.id.checkBox_samples_sensor); - samplesEditBox = findViewById(R.id.editBox_samples_sensors); - timeGapSeekbar = findViewById(R.id.seekBar_timegap_sensor); - timeGapLabel = findViewById(R.id.tv_timegap_label); - playPauseButton = findViewById(R.id.imageButton_play_pause_sensor); - setSensorDock(); - sensorDock.setVisibility(View.VISIBLE); - - scienceLab = ScienceLabCommon.scienceLab; - I2C i2c = scienceLab.i2c; - entries = new ArrayList<>(); + I2C i2c = getScienceLab().i2c; try { sensorADS1115 = new ADS1115(i2c); } catch (IOException | InterruptedException e) { - e.printStackTrace(); + Log.e(TAG, "Sensor initialization failed.", e); } - Runnable runnable = new Runnable() { - @Override - public void run() { - while (true) { - if (scienceLab.isConnected() && shouldPlay()) { - sensorDataFetch = new SensorADS1115.SensorDataFetch(); - sensorDataFetch.execute(); - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - } - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - try { - Thread.sleep(timeGap); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - }; - new Thread(runnable).start(); + sensorDataFetch = new SensorDataFetch(); tvSensorADS1115 = findViewById(R.id.tv_sensor_ads1115); mChart = findViewById(R.id.chart_sensor_ads); @@ -167,111 +100,52 @@ public void run() { y.setLabelCount(10); y2.setDrawGridLines(false); - } - private boolean shouldPlay() { - if (play) { - if (indefiniteSamplesCheckBox.isChecked()) - return true; - else if (counter >= 0) { - counter--; - return true; - } else { - play = false; - return false; - } + if (savedInstanceState == null) { + entries = new ArrayList<>(); } else { - return false; - } - } + tvSensorADS1115.setText(savedInstanceState.getString(KEY_VALUE)); - private void setSensorDock() { - play = false; - runIndefinitely = true; - timeGap = 100; - final int step = 1; - final int max = 1000; - final int min = 100; - - playPauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (play && scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else if (!scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else { - playPauseButton.setImageResource(R.drawable.circle_pause_button); - play = true; - if (!indefiniteSamplesCheckBox.isChecked()) { - counter = Integer.parseInt(samplesEditBox.getText().toString()); - } - } - } - }); - sensorDock.setVisibility(View.VISIBLE); - - indefiniteSamplesCheckBox.setChecked(true); - samplesEditBox.setEnabled(false); - indefiniteSamplesCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - runIndefinitely = true; - samplesEditBox.setEnabled(false); - } else { - runIndefinitely = false; - samplesEditBox.setEnabled(true); - } - } - }); - - timeGapSeekbar.setMax((max - min) / step); - timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - timeGap = min + (progress * step); - timeGapLabel.setText(timeGap + "ms"); - } + entries = savedInstanceState.getParcelableArrayList(KEY_ENTRIES); - @Override - public void onStartTrackingTouch(SeekBar seekBar) { + sensorDataFetch.updateUi(); + } + } - } + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); - @Override - public void onStopTrackingTouch(SeekBar seekBar) { + outState.putString(KEY_VALUE, tvSensorADS1115.getText().toString()); - } - }); + outState.putParcelableArrayList(KEY_ENTRIES, entries); } - private class SensorDataFetch extends AsyncTask { + private class SensorDataFetch extends AbstractSensorActivity.SensorDataFetch { private int dataADS1115; - private long timeElapsed; + /* Initialization required if updateUi is executed before getSensorData */ + private float timeElapsed = getTimeElapsed(); @Override - protected Void doInBackground(Void... params) { + public void getSensorData() { try { if (sensorADS1115 != null) { dataADS1115 = sensorADS1115.getRaw(); } } catch (IOException | InterruptedException e) { - e.printStackTrace(); + Log.e(TAG, "Error getting sensor data.", e); } - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; - entries.add(new Entry((float) timeElapsed, dataADS1115)); - - return null; + timeElapsed = getTimeElapsed(); + entries.add(new Entry(timeElapsed, dataADS1115)); } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - tvSensorADS1115.setText(String.valueOf(dataADS1115)); + @Override + public void updateUi() { + if (isSensorDataAcquired()) { + tvSensorADS1115.setText(String.valueOf(dataADS1115)); + } LineDataSet dataSet = new LineDataSet(entries, getString(R.string.bx)); dataSet.setDrawCircles(true); @@ -279,24 +153,21 @@ protected void onPostExecute(Void aVoid) { mChart.setData(data); mChart.notifyDataSetChanged(); mChart.setVisibleXRangeMaximum(10); - mChart.moveViewToX(data.getEntryCount()); - mChart.invalidate(); - samplesEditBox.setText(String.valueOf(counter)); - if (counter == 0 && !runIndefinitely) { - play = false; - playPauseButton.setImageResource(R.drawable.circle_play_button); - } - synchronized (lock) { - lock.notify(); - } + mChart.moveViewToX(timeElapsed); } } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; + protected AbstractSensorActivity.SensorDataFetch getSensorDataFetch() { + return sensorDataFetch; + } + + protected int getLayoutResId() { + return R.layout.sensor_ads1115; + } + + @Override + protected int getTitleResId() { + return R.string.ads1115; } } diff --git a/app/src/main/java/io/pslab/sensors/SensorAPDS9960.java b/app/src/main/java/io/pslab/sensors/SensorAPDS9960.java index 81717129d..7ef54a118 100644 --- a/app/src/main/java/io/pslab/sensors/SensorAPDS9960.java +++ b/app/src/main/java/io/pslab/sensors/SensorAPDS9960.java @@ -1,23 +1,13 @@ package io.pslab.sensors; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; -import android.view.MenuItem; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.RelativeLayout; -import android.widget.SeekBar; import android.widget.Spinner; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.Legend; @@ -32,106 +22,52 @@ import io.pslab.DataFormatter; import io.pslab.R; -import io.pslab.communication.ScienceLab; import io.pslab.communication.peripherals.I2C; import io.pslab.communication.sensors.APDS9960; -import io.pslab.others.ScienceLabCommon; -public class SensorAPDS9960 extends AppCompatActivity { +public class SensorAPDS9960 extends AbstractSensorActivity { private static final String TAG = SensorAPDS9960.class.getSimpleName(); - private static int counter; - private final Object lock = new Object(); - private ScienceLab scienceLab; - private SensorAPDS9960.SensorDataFetch sensorDataFetch; + + private static final String KEY_ENTRIES_LUX = TAG + "_entries_lux"; + private static final String KEY_ENTRIES_PROXIMITY = TAG + "_entries_proximity"; + private static final String KEY_VALUE_RED = TAG + "_value_red"; + private static final String KEY_VALUE_GREEN = TAG + "_value_green"; + private static final String KEY_VALUE_BLUE = TAG + "_value_blue"; + private static final String KEY_VALUE_CLEAR = TAG + "_value_clear"; + private static final String KEY_VALUE_PROXIMITY = TAG + "_value_proximity"; + private static final String KEY_VALUE_GESTURE = TAG + "_value_gesture"; + private static final String KEY_POS_MODE = TAG + "_pos_mode"; + + private SensorDataFetch sensorDataFetch; + private APDS9960 sensorAPDS9960; + + private ArrayList entriesLux; + private ArrayList entriesProximity; + + private LineChart mChartLux; + private LineChart mChartProximity; + private Spinner spinnerMode; private TextView tvSensorAPDS9960Red; private TextView tvSensorAPDS9960Green; private TextView tvSensorAPDS9960Blue; private TextView tvSensorAPDS9960Clear; private TextView tvSensorAPDS9960Proximity; private TextView tvSensorAPDS9960Gesture; - private APDS9960 sensorAPDS9960; - private LineChart mChartLux; - private LineChart mChartProximity; - private long startTime; - private int flag; - private ArrayList entriesLux; - private ArrayList entriesProximity; - private RelativeLayout sensorDock; - private CheckBox indefiniteSamplesCheckBox; - private EditText samplesEditBox; - private SeekBar timeGapSeekbar; - private TextView timeGapLabel; - private ImageButton playPauseButton; - private Spinner spinnerMode; - private boolean play; - private boolean runIndefinitely; - private int timeGap; @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sensor_apds9960); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.apds9960); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } - sensorDock = findViewById(R.id.sensor_control_dock_layout); - indefiniteSamplesCheckBox = findViewById(R.id.checkBox_samples_sensor); - samplesEditBox = findViewById(R.id.editBox_samples_sensors); - timeGapSeekbar = findViewById(R.id.seekBar_timegap_sensor); - timeGapLabel = findViewById(R.id.tv_timegap_label); - playPauseButton = findViewById(R.id.imageButton_play_pause_sensor); - setSensorDock(); - sensorDock.setVisibility(View.VISIBLE); spinnerMode = findViewById(R.id.spinner_sensor_apds9960); - scienceLab = ScienceLabCommon.scienceLab; - I2C i2c = scienceLab.i2c; + I2C i2c = getScienceLab().i2c; try { - sensorAPDS9960 = new APDS9960(i2c, scienceLab); + sensorAPDS9960 = new APDS9960(i2c, getScienceLab()); } catch (Exception e) { - Log.e(TAG, "Sensor initialization failed."); + Log.e(TAG, "Sensor initialization failed.", e); } - entriesLux = new ArrayList<>(); - entriesProximity = new ArrayList<>(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - while (true) { - if (scienceLab.isConnected() && shouldPlay()) { - sensorDataFetch = new SensorAPDS9960.SensorDataFetch(); - sensorDataFetch.execute(); - - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - } - - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - Log.e(TAG, "Thread interrupted while waiting."); - } - } - try { - Thread.sleep(timeGap); - } catch (InterruptedException e) { - Log.e(TAG, "Thread interrupted during sleep."); - } - } - } - } - }; - new Thread(runnable).start(); + sensorDataFetch = new SensorDataFetch(); tvSensorAPDS9960Red = findViewById(R.id.tv_sensor_apds9960_red); tvSensorAPDS9960Green = findViewById(R.id.tv_sensor_apds9960_green); @@ -209,97 +145,55 @@ public void run() { yProximity.setLabelCount(10); yProximity2.setDrawGridLines(false); - } - private boolean shouldPlay() { - if (play) { - if (indefiniteSamplesCheckBox.isChecked()) - return true; - else if (counter >= 0) { - counter--; - return true; - } else { - play = false; - return false; - } + if (savedInstanceState == null) { + entriesLux = new ArrayList<>(); + entriesProximity = new ArrayList<>(); } else { - return false; + spinnerMode.setSelection(savedInstanceState.getInt(KEY_POS_MODE)); + + tvSensorAPDS9960Red.setText(savedInstanceState.getString(KEY_VALUE_RED)); + tvSensorAPDS9960Green.setText(savedInstanceState.getString(KEY_VALUE_GREEN)); + tvSensorAPDS9960Blue.setText(savedInstanceState.getString(KEY_VALUE_BLUE)); + tvSensorAPDS9960Clear.setText(savedInstanceState.getString(KEY_VALUE_CLEAR)); + tvSensorAPDS9960Proximity.setText(savedInstanceState.getString(KEY_VALUE_PROXIMITY)); + tvSensorAPDS9960Gesture.setText(savedInstanceState.getString(KEY_VALUE_GESTURE)); + + entriesLux = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_LUX); + entriesProximity = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_PROXIMITY); + + sensorDataFetch.updateUi(); } } - private void setSensorDock() { - play = false; - runIndefinitely = true; - timeGap = 100; - final int step = 1; - final int max = 1000; - final int min = 100; - - playPauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (play && scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else if (!scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else { - playPauseButton.setImageResource(R.drawable.circle_pause_button); - play = true; - if (!indefiniteSamplesCheckBox.isChecked()) { - counter = Integer.parseInt(samplesEditBox.getText().toString()); - } - } - } - }); - sensorDock.setVisibility(View.VISIBLE); - - indefiniteSamplesCheckBox.setChecked(true); - samplesEditBox.setEnabled(false); - indefiniteSamplesCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - runIndefinitely = true; - samplesEditBox.setEnabled(false); - } else { - runIndefinitely = false; - samplesEditBox.setEnabled(true); - } - } - }); - - timeGapSeekbar.setMax((max - min) / step); - timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - timeGap = min + (progress * step); - timeGapLabel.setText(timeGap + "ms"); - } + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - // Do nothing - } + outState.putInt(KEY_POS_MODE, spinnerMode.getSelectedItemPosition()); - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - // Do nothing - } - }); + outState.putString(KEY_VALUE_RED, tvSensorAPDS9960Red.getText().toString()); + outState.putString(KEY_VALUE_GREEN, tvSensorAPDS9960Green.getText().toString()); + outState.putString(KEY_VALUE_BLUE, tvSensorAPDS9960Blue.getText().toString()); + outState.putString(KEY_VALUE_CLEAR, tvSensorAPDS9960Clear.getText().toString()); + outState.putString(KEY_VALUE_PROXIMITY, tvSensorAPDS9960Proximity.getText().toString()); + outState.putString(KEY_VALUE_GESTURE, tvSensorAPDS9960Gesture.getText().toString()); + + outState.putParcelableArrayList(KEY_ENTRIES_LUX, entriesLux); + outState.putParcelableArrayList(KEY_ENTRIES_PROXIMITY, entriesProximity); } - private class SensorDataFetch extends AsyncTask { + private class SensorDataFetch extends AbstractSensorActivity.SensorDataFetch { private int[] dataAPDS9960Color; private double dataAPDS9960Lux; private int dataAPDS9960Proximity; private int dataAPDS9960Gesture; - private long timeElapsed; + /* Initialization required if updateUi is executed before getSensorData */ + private float timeElapsed = getTimeElapsed(); @Override - protected Void doInBackground(Void... params) { + public void getSensorData() { try { if (sensorAPDS9960 != null) { if (spinnerMode.getSelectedItemPosition() == 0) { @@ -317,22 +211,23 @@ protected Void doInBackground(Void... params) { } } } catch (IOException | InterruptedException e) { - e.printStackTrace(); + Log.e(TAG, "Error getting sensor data.", e); } - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; - entriesLux.add(new Entry((float) timeElapsed, (float) dataAPDS9960Lux)); - entriesProximity.add(new Entry((float) timeElapsed, dataAPDS9960Proximity)); - return null; + timeElapsed = getTimeElapsed(); + entriesLux.add(new Entry(timeElapsed, (float) dataAPDS9960Lux)); + entriesProximity.add(new Entry(timeElapsed, dataAPDS9960Proximity)); } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); + public void updateUi() { if (spinnerMode.getSelectedItemPosition() == 0) { - tvSensorAPDS9960Red.setText(DataFormatter.formatDouble(dataAPDS9960Color[0], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorAPDS9960Green.setText(DataFormatter.formatDouble(dataAPDS9960Color[1], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorAPDS9960Blue.setText(DataFormatter.formatDouble(dataAPDS9960Color[2], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorAPDS9960Clear.setText(DataFormatter.formatDouble(dataAPDS9960Color[3], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorAPDS9960Proximity.setText(DataFormatter.formatDouble(dataAPDS9960Proximity, DataFormatter.HIGH_PRECISION_FORMAT)); + + if (isSensorDataAcquired()) { + tvSensorAPDS9960Red.setText(DataFormatter.formatDouble(dataAPDS9960Color[0], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorAPDS9960Green.setText(DataFormatter.formatDouble(dataAPDS9960Color[1], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorAPDS9960Blue.setText(DataFormatter.formatDouble(dataAPDS9960Color[2], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorAPDS9960Clear.setText(DataFormatter.formatDouble(dataAPDS9960Color[3], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorAPDS9960Proximity.setText(DataFormatter.formatDouble(dataAPDS9960Proximity, DataFormatter.HIGH_PRECISION_FORMAT)); + } LineDataSet dataSet1 = new LineDataSet(entriesLux, getString(R.string.light_lux)); LineDataSet dataSet2 = new LineDataSet(entriesProximity, getString(R.string.proximity)); @@ -344,16 +239,14 @@ protected void onPostExecute(Void aVoid) { mChartLux.setData(data); mChartLux.notifyDataSetChanged(); mChartLux.setVisibleXRangeMaximum(10); - mChartLux.moveViewToX(data.getEntryCount()); - mChartLux.invalidate(); + mChartLux.moveViewToX(timeElapsed); LineData data2 = new LineData(dataSet2); mChartProximity.setData(data2); mChartProximity.notifyDataSetChanged(); mChartProximity.setVisibleXRangeMaximum(10); - mChartProximity.moveViewToX(data2.getEntryCount()); - mChartProximity.invalidate(); - } else { + mChartProximity.moveViewToX(timeElapsed); + } else if (isSensorDataAcquired()) { switch (dataAPDS9960Gesture) { case 1: tvSensorAPDS9960Gesture.setText(R.string.up); @@ -371,23 +264,21 @@ protected void onPostExecute(Void aVoid) { break; } } - - samplesEditBox.setText(String.valueOf(counter)); - if (counter == 0 && !runIndefinitely) { - play = false; - playPauseButton.setImageResource(R.drawable.circle_play_button); - } - synchronized (lock) { - lock.notify(); - } } } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; + protected AbstractSensorActivity.SensorDataFetch getSensorDataFetch() { + return sensorDataFetch; + } + + @Override + protected int getLayoutResId() { + return R.layout.sensor_apds9960; + } + + @Override + protected int getTitleResId() { + return R.string.apds9960; } } diff --git a/app/src/main/java/io/pslab/sensors/SensorBMP180.java b/app/src/main/java/io/pslab/sensors/SensorBMP180.java index 449366240..a4c824cce 100644 --- a/app/src/main/java/io/pslab/sensors/SensorBMP180.java +++ b/app/src/main/java/io/pslab/sensors/SensorBMP180.java @@ -1,21 +1,12 @@ package io.pslab.sensors; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; -import android.view.MenuItem; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.RelativeLayout; -import android.widget.SeekBar; +import android.util.Log; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.Legend; @@ -30,104 +21,45 @@ import io.pslab.DataFormatter; import io.pslab.R; -import io.pslab.communication.ScienceLab; import io.pslab.communication.peripherals.I2C; import io.pslab.communication.sensors.BMP180; -import io.pslab.others.ScienceLabCommon; -/** - * Created by Harsh on 6/6/18. - */ +public class SensorBMP180 extends AbstractSensorActivity { + private static final String TAG = SensorBMP180.class.getSimpleName(); -public class SensorBMP180 extends AppCompatActivity { - private static int counter; - private final Object lock = new Object(); - private ScienceLab scienceLab; - private SensorBMP180.SensorDataFetch sensorDataFetch; - private TextView tvSensorBMP180Temp; - private TextView tvSensorBMP180Altitude; - private TextView tvSensorBMP180Pressure; + private static final String KEY_ENTRIES_TEMPERATURE = TAG + "_entries_temperature"; + private static final String KEY_ENTRIES_ALTITUDE = TAG + "_entries_altitude"; + private static final String KEY_ENTRIES_PRESSURE = TAG + "_entries_pressure"; + private static final String KEY_VALUE_TEMPERATURE = TAG + "_value_temperature"; + private static final String KEY_VALUE_ALTITUDE = TAG + "_value_altitude"; + private static final String KEY_VALUE_PRESSURE = TAG + "_value_pressure"; + + private SensorDataFetch sensorDataFetch; private BMP180 sensorBMP180; - private LineChart mChartTemperature; - private LineChart mChartAltitude; - private LineChart mChartPressure; - private long startTime; - private int flag; + private ArrayList entriesTemperature; private ArrayList entriesAltitude; private ArrayList entriesPressure; - private RelativeLayout sensorDock; - private CheckBox indefiniteSamplesCheckBox; - private EditText samplesEditBox; - private SeekBar timeGapSeekbar; - private TextView timeGapLabel; - private ImageButton playPauseButton; - private boolean play; - private boolean runIndefinitely; - private int timeGap; + + private LineChart mChartTemperature; + private LineChart mChartAltitude; + private LineChart mChartPressure; + private TextView tvSensorBMP180Temp; + private TextView tvSensorBMP180Altitude; + private TextView tvSensorBMP180Pressure; @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sensor_bmp180); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.bmp180); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } - sensorDock = findViewById(R.id.sensor_control_dock_layout); - indefiniteSamplesCheckBox = findViewById(R.id.checkBox_samples_sensor); - samplesEditBox = findViewById(R.id.editBox_samples_sensors); - timeGapSeekbar = findViewById(R.id.seekBar_timegap_sensor); - timeGapLabel = findViewById(R.id.tv_timegap_label); - playPauseButton = findViewById(R.id.imageButton_play_pause_sensor); - setSensorDock(); - sensorDock.setVisibility(View.VISIBLE); - - scienceLab = ScienceLabCommon.scienceLab; - I2C i2c = scienceLab.i2c; + I2C i2c = getScienceLab().i2c; try { - sensorBMP180 = new BMP180(i2c, scienceLab); + sensorBMP180 = new BMP180(i2c, getScienceLab()); } catch (IOException | InterruptedException e) { - e.printStackTrace(); + Log.e(TAG, "Sensor initialization failed.", e); } - Runnable runnable = new Runnable() { - @Override - public void run() { - while (true) { - if (scienceLab.isConnected() && shouldPlay()) { - sensorDataFetch = new SensorBMP180.SensorDataFetch(); - sensorDataFetch.execute(); - - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - } - - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - try { - Thread.sleep(timeGap); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - } - } - }; - new Thread(runnable).start(); + sensorDataFetch = new SensorDataFetch(); tvSensorBMP180Temp = findViewById(R.id.tv_sensor_bmp180_temp); tvSensorBMP180Altitude = findViewById(R.id.tv_sensor_bmp180_altitude); @@ -149,10 +81,6 @@ public void run() { YAxis yPressure = mChartPressure.getAxisLeft(); YAxis yPressure2 = mChartPressure.getAxisRight(); - entriesTemperature = new ArrayList<>(); - entriesAltitude = new ArrayList<>(); - entriesPressure = new ArrayList<>(); - mChartTemperature.setTouchEnabled(true); mChartTemperature.setHighlightPerDragEnabled(true); mChartTemperature.setDragEnabled(true); @@ -242,114 +170,66 @@ public void run() { yPressure.setLabelCount(10); yPressure2.setDrawGridLines(false); - } - private boolean shouldPlay() { - if (play && scienceLab.isConnected()) { - if (indefiniteSamplesCheckBox.isChecked()) - return true; - else if (counter >= 0) { - counter--; - return true; - } else { - play = false; - return false; - } + if (savedInstanceState == null) { + entriesTemperature = new ArrayList<>(); + entriesAltitude = new ArrayList<>(); + entriesPressure = new ArrayList<>(); } else { - return false; - } - } + tvSensorBMP180Temp.setText(savedInstanceState.getString(KEY_VALUE_TEMPERATURE)); + tvSensorBMP180Altitude.setText(savedInstanceState.getString(KEY_VALUE_ALTITUDE)); + tvSensorBMP180Pressure.setText(savedInstanceState.getString(KEY_VALUE_PRESSURE)); - private void setSensorDock() { - play = false; - runIndefinitely = true; - timeGap = 100; - final int step = 1; - final int max = 1000; - final int min = 100; - - playPauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (play && scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else if (!scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else { - playPauseButton.setImageResource(R.drawable.circle_pause_button); - play = true; - if (!indefiniteSamplesCheckBox.isChecked()) { - counter = Integer.parseInt(samplesEditBox.getText().toString()); - } - } - } - }); - sensorDock.setVisibility(View.VISIBLE); - - indefiniteSamplesCheckBox.setChecked(true); - samplesEditBox.setEnabled(false); - indefiniteSamplesCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - runIndefinitely = true; - samplesEditBox.setEnabled(false); - } else { - runIndefinitely = false; - samplesEditBox.setEnabled(true); - } - } - }); - - timeGapSeekbar.setMax((max - min) / step); - timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - timeGap = min + (progress * step); - timeGapLabel.setText(timeGap + "ms"); - } + entriesTemperature = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_TEMPERATURE); + entriesAltitude = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_ALTITUDE); + entriesPressure = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_PRESSURE); - @Override - public void onStartTrackingTouch(SeekBar seekBar) { + sensorDataFetch.updateUi(); + } + } - } + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); - @Override - public void onStopTrackingTouch(SeekBar seekBar) { + outState.putString(KEY_VALUE_TEMPERATURE, tvSensorBMP180Temp.getText().toString()); + outState.putString(KEY_VALUE_ALTITUDE, tvSensorBMP180Altitude.getText().toString()); + outState.putString(KEY_VALUE_PRESSURE, tvSensorBMP180Pressure.getText().toString()); - } - }); + outState.putParcelableArrayList(KEY_ENTRIES_TEMPERATURE, entriesTemperature); + outState.putParcelableArrayList(KEY_ENTRIES_ALTITUDE, entriesAltitude); + outState.putParcelableArrayList(KEY_ENTRIES_PRESSURE, entriesPressure); } - private class SensorDataFetch extends AsyncTask { + private class SensorDataFetch extends AbstractSensorActivity.SensorDataFetch { private double[] dataBMP180 = new double[3]; - private long timeElapsed; + /* Initialization required if updateUi is executed before getSensorData */ + private float timeElapsed = getTimeElapsed(); @Override - protected Void doInBackground(Void... params) { + public void getSensorData() { try { - if (sensorBMP180 != null && scienceLab.isConnected()) { + if (sensorBMP180 != null && getScienceLab().isConnected()) { dataBMP180 = sensorBMP180.getRaw(); } } catch (IOException | InterruptedException e) { - e.printStackTrace(); + Log.e(TAG, "Error getting sensor data.", e); } - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; - entriesTemperature.add(new Entry((float) timeElapsed, (float) dataBMP180[0])); - entriesAltitude.add(new Entry((float) timeElapsed, (float) dataBMP180[1])); - entriesPressure.add(new Entry((float) timeElapsed, (float) dataBMP180[2])); - return null; + timeElapsed = getTimeElapsed(); + entriesTemperature.add(new Entry(timeElapsed, (float) dataBMP180[0])); + entriesAltitude.add(new Entry(timeElapsed, (float) dataBMP180[1])); + entriesPressure.add(new Entry(timeElapsed, (float) dataBMP180[2])); } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - tvSensorBMP180Temp.setText(DataFormatter.formatDouble(dataBMP180[0], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorBMP180Altitude.setText(DataFormatter.formatDouble(dataBMP180[1], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorBMP180Pressure.setText(DataFormatter.formatDouble(dataBMP180[2], DataFormatter.HIGH_PRECISION_FORMAT)); + public void updateUi() { + + if (isSensorDataAcquired()) { + tvSensorBMP180Temp.setText(DataFormatter.formatDouble(dataBMP180[0], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorBMP180Altitude.setText(DataFormatter.formatDouble(dataBMP180[1], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorBMP180Pressure.setText(DataFormatter.formatDouble(dataBMP180[2], DataFormatter.HIGH_PRECISION_FORMAT)); + } LineDataSet dataSet1 = new LineDataSet(entriesTemperature, getString(R.string.temperature)); LineDataSet dataSet2 = new LineDataSet(entriesAltitude, getString(R.string.altitude)); @@ -363,38 +243,34 @@ protected void onPostExecute(Void aVoid) { mChartTemperature.setData(data); mChartTemperature.notifyDataSetChanged(); mChartTemperature.setVisibleXRangeMaximum(10); - mChartTemperature.moveViewToX(data.getEntryCount()); - mChartTemperature.invalidate(); + mChartTemperature.moveViewToX(timeElapsed); LineData data2 = new LineData(dataSet2); mChartAltitude.setData(data2); mChartAltitude.notifyDataSetChanged(); mChartAltitude.setVisibleXRangeMaximum(10); - mChartAltitude.moveViewToX(data.getEntryCount()); - mChartAltitude.invalidate(); + mChartAltitude.moveViewToX(timeElapsed); LineData data3 = new LineData(dataSet3); mChartPressure.setData(data3); mChartPressure.notifyDataSetChanged(); mChartPressure.setVisibleXRangeMaximum(10); - mChartPressure.moveViewToX(data.getEntryCount()); - mChartPressure.invalidate(); - samplesEditBox.setText(String.valueOf(counter)); - if (counter == 0 && !runIndefinitely) { - play = false; - playPauseButton.setImageResource(R.drawable.circle_play_button); - } - synchronized (lock) { - lock.notify(); - } + mChartPressure.moveViewToX(timeElapsed); } } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; + protected AbstractSensorActivity.SensorDataFetch getSensorDataFetch() { + return sensorDataFetch; + } + + @Override + protected int getLayoutResId() { + return R.layout.sensor_bmp180; + } + + @Override + protected int getTitleResId() { + return R.string.bmp180; } } diff --git a/app/src/main/java/io/pslab/sensors/SensorCCS811.java b/app/src/main/java/io/pslab/sensors/SensorCCS811.java index c2218009e..468879f2e 100644 --- a/app/src/main/java/io/pslab/sensors/SensorCCS811.java +++ b/app/src/main/java/io/pslab/sensors/SensorCCS811.java @@ -1,21 +1,12 @@ package io.pslab.sensors; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; -import android.view.MenuItem; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.RelativeLayout; -import android.widget.SeekBar; +import android.util.Log; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.Legend; @@ -30,101 +21,40 @@ import io.pslab.DataFormatter; import io.pslab.R; -import io.pslab.communication.ScienceLab; import io.pslab.communication.peripherals.I2C; import io.pslab.communication.sensors.CCS811; -import io.pslab.communication.sensors.SHT21; -import io.pslab.others.ScienceLabCommon; - -public class SensorCCS811 extends AppCompatActivity { - private static int counter; - private final Object lock = new Object(); - private ScienceLab scienceLab; - private SensorCCS811.SensorDataFetch sensorDataFetch; - private TextView tvSensorCCS811eCO2; - private TextView tvSensorCCS811TVOC; + +public class SensorCCS811 extends AbstractSensorActivity { + private static final String TAG = SensorCCS811.class.getSimpleName(); + + private static final String KEY_ENTRIES_ECO2 = TAG + "_entries_eco2"; + private static final String KEY_ENTRIES_TVOC = TAG + "_entries_tvoc"; + private static final String KEY_VALUE_ECO2 = TAG + "_value_eco2"; + private static final String KEY_VALUE_TVOC = TAG + "_value_tvoc"; + + private SensorDataFetch sensorDataFetch; private CCS811 sensorCCS811; - private LineChart mCharteCO2; - private LineChart mChartTVOC; - private long startTime; - private int flag; + private ArrayList entrieseCO2; private ArrayList entriesTVOC; - private RelativeLayout sensorDock; - private CheckBox indefiniteSamplesCheckBox; - private EditText samplesEditBox; - private SeekBar timeGapSeekbar; - private TextView timeGapLabel; - private ImageButton playPauseButton; - private boolean play; - private boolean runIndefinitely; - private int timeGap; + + private LineChart mCharteCO2; + private LineChart mChartTVOC; + private TextView tvSensorCCS811eCO2; + private TextView tvSensorCCS811TVOC; @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sensor_ccs811); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.ccs811); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } - sensorDock = findViewById(R.id.sensor_control_dock_layout); - indefiniteSamplesCheckBox = findViewById(R.id.checkBox_samples_sensor); - samplesEditBox = findViewById(R.id.editBox_samples_sensors); - timeGapSeekbar = findViewById(R.id.seekBar_timegap_sensor); - timeGapLabel = findViewById(R.id.tv_timegap_label); - playPauseButton = findViewById(R.id.imageButton_play_pause_sensor); - setSensorDock(); - sensorDock.setVisibility(View.VISIBLE); - - scienceLab = ScienceLabCommon.scienceLab; - I2C i2c = scienceLab.i2c; + I2C i2c = getScienceLab().i2c; try { - sensorCCS811 = new CCS811(i2c, scienceLab); + sensorCCS811 = new CCS811(i2c, getScienceLab()); } catch (Exception e) { - e.printStackTrace(); + Log.e(TAG, "Sensor initialization failed.", e); } - entrieseCO2 = new ArrayList<>(); - entriesTVOC = new ArrayList<>(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - while (true) { - if (scienceLab.isConnected() && shouldPlay()) { - sensorDataFetch = new SensorCCS811.SensorDataFetch(); - sensorDataFetch.execute(); - - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - } - - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - try { - Thread.sleep(timeGap); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - }; - new Thread(runnable).start(); + sensorDataFetch = new SensorDataFetch(); tvSensorCCS811eCO2 = findViewById(R.id.tv_sensor_ccs811_eCO2); tvSensorCCS811TVOC = findViewById(R.id.tv_sensor_ccs811_TVOC); @@ -199,115 +129,60 @@ public void run() { yTVOC2.setDrawGridLines(false); - } - - private boolean shouldPlay() { - if (play) { - if (indefiniteSamplesCheckBox.isChecked()) - return true; - else if (counter >= 0) { - counter--; - return true; - } else { - play = false; - return false; - } + if (savedInstanceState == null) { + entrieseCO2 = new ArrayList<>(); + entriesTVOC = new ArrayList<>(); } else { - return false; + tvSensorCCS811eCO2.setText(savedInstanceState.getString(KEY_VALUE_ECO2)); + tvSensorCCS811TVOC.setText(savedInstanceState.getString(KEY_VALUE_TVOC)); + + entrieseCO2 = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_ECO2); + entriesTVOC = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_TVOC); + + sensorDataFetch.updateUi(); } } - private void setSensorDock() { - play = false; - runIndefinitely = true; - timeGap = 100; - final int step = 1; - final int max = 1000; - final int min = 100; - - playPauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (play && scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else if (!scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else { - playPauseButton.setImageResource(R.drawable.circle_pause_button); - play = true; - if (!indefiniteSamplesCheckBox.isChecked()) { - counter = Integer.parseInt(samplesEditBox.getText().toString()); - } - } - } - }); - sensorDock.setVisibility(View.VISIBLE); - - indefiniteSamplesCheckBox.setChecked(true); - samplesEditBox.setEnabled(false); - indefiniteSamplesCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - runIndefinitely = true; - samplesEditBox.setEnabled(false); - } else { - runIndefinitely = false; - samplesEditBox.setEnabled(true); - } - } - }); - - timeGapSeekbar.setMax((max - min) / step); - timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - timeGap = min + (progress * step); - timeGapLabel.setText(timeGap + "ms"); - } + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - // Do nothing - } + outState.putString(KEY_VALUE_ECO2, tvSensorCCS811eCO2.getText().toString()); + outState.putString(KEY_VALUE_TVOC, tvSensorCCS811TVOC.getText().toString()); - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - // Do nothing - } - }); + outState.putParcelableArrayList(KEY_ENTRIES_ECO2, entrieseCO2); + outState.putParcelableArrayList(KEY_ENTRIES_TVOC, entriesTVOC); } - private class SensorDataFetch extends AsyncTask { + private class SensorDataFetch extends AbstractSensorActivity.SensorDataFetch { - private int[] dataCS811; private int dataCCS811eCO2; private int dataCCS811TVOC; - private long timeElapsed; + /* Initialization required if updateUi is executed before getSensorData */ + private float timeElapsed = getTimeElapsed(); @Override - protected Void doInBackground(Void... params) { + public void getSensorData() { try { if (sensorCCS811 != null) { - dataCS811 = sensorCCS811.getRaw(); + int[] dataCS811 = sensorCCS811.getRaw(); dataCCS811eCO2 = dataCS811[0]; dataCCS811TVOC = dataCS811[1]; } } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error getting sensor data.", e); } - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; - entrieseCO2.add(new Entry((float) timeElapsed, dataCCS811eCO2)); - entriesTVOC.add(new Entry((float) timeElapsed, dataCCS811TVOC)); - return null; + timeElapsed = getTimeElapsed(); + entrieseCO2.add(new Entry(timeElapsed, dataCCS811eCO2)); + entriesTVOC.add(new Entry(timeElapsed, dataCCS811TVOC)); } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - tvSensorCCS811eCO2.setText(DataFormatter.formatDouble(dataCCS811eCO2, DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorCCS811TVOC.setText(DataFormatter.formatDouble(dataCCS811TVOC, DataFormatter.HIGH_PRECISION_FORMAT)); + public void updateUi() { + + if (isSensorDataAcquired()) { + tvSensorCCS811eCO2.setText(DataFormatter.formatDouble(dataCCS811eCO2, DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorCCS811TVOC.setText(DataFormatter.formatDouble(dataCCS811TVOC, DataFormatter.HIGH_PRECISION_FORMAT)); + } LineDataSet dataSet1 = new LineDataSet(entrieseCO2, getString(R.string.eCO2)); LineDataSet dataSet2 = new LineDataSet(entriesTVOC, getString(R.string.eTVOC)); @@ -319,31 +194,28 @@ protected void onPostExecute(Void aVoid) { mCharteCO2.setData(data); mCharteCO2.notifyDataSetChanged(); mCharteCO2.setVisibleXRangeMaximum(10); - mCharteCO2.moveViewToX(data.getEntryCount()); - mCharteCO2.invalidate(); + mCharteCO2.moveViewToX(timeElapsed); LineData data2 = new LineData(dataSet2); mChartTVOC.setData(data2); mChartTVOC.notifyDataSetChanged(); mChartTVOC.setVisibleXRangeMaximum(10); - mChartTVOC.moveViewToX(data2.getEntryCount()); - mChartTVOC.invalidate(); - samplesEditBox.setText(String.valueOf(counter)); - if (counter == 0 && !runIndefinitely) { - play = false; - playPauseButton.setImageResource(R.drawable.circle_play_button); - } - synchronized (lock) { - lock.notify(); - } + mChartTVOC.moveViewToX(timeElapsed); } } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; + protected AbstractSensorActivity.SensorDataFetch getSensorDataFetch() { + return sensorDataFetch; + } + + @Override + protected int getLayoutResId() { + return R.layout.sensor_ccs811; + } + + @Override + protected int getTitleResId() { + return R.string.ccs811; } } diff --git a/app/src/main/java/io/pslab/sensors/SensorHMC5883L.java b/app/src/main/java/io/pslab/sensors/SensorHMC5883L.java index 395dfd7a8..efff0c98b 100644 --- a/app/src/main/java/io/pslab/sensors/SensorHMC5883L.java +++ b/app/src/main/java/io/pslab/sensors/SensorHMC5883L.java @@ -1,21 +1,12 @@ package io.pslab.sensors; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; -import android.view.MenuItem; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.RelativeLayout; -import android.widget.SeekBar; +import android.util.Log; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.Legend; @@ -32,104 +23,43 @@ import io.pslab.DataFormatter; import io.pslab.R; -import io.pslab.communication.ScienceLab; import io.pslab.communication.peripherals.I2C; import io.pslab.communication.sensors.HMC5883L; -import io.pslab.others.ScienceLabCommon; -/** - * Created by Harsh on 6/6/18. - */ +public class SensorHMC5883L extends AbstractSensorActivity { + private static final String TAG = SensorHMC5883L.class.getSimpleName(); -public class SensorHMC5883L extends AppCompatActivity { - private static int counter; - private final Object lock = new Object(); - private ScienceLab scienceLab; - private SensorHMC5883L.SensorDataFetch sensorDataFetch; - private TextView tvSensorHMC5883Lbx; - private TextView tvSensorHMC5883Lby; - private TextView tvSensorHMC5883Lbz; + private static final String KEY_ENTRIES_BX = TAG + "_entries_bx"; + private static final String KEY_ENTRIES_BY = TAG + "_entries_by"; + private static final String KEY_ENTRIES_BZ = TAG + "_entries_bz"; + private static final String KEY_VALUE_BX = TAG + "_value_bx"; + private static final String KEY_VALUE_BY = TAG + "_value_by"; + private static final String KEY_VALUE_BZ = TAG + "_value_bz"; + + private SensorDataFetch sensorDataFetch; private HMC5883L sensorHMC5883L; - private LineChart mChart; - private long startTime; - private int flag; + private ArrayList entriesBx; private ArrayList entriesBy; private ArrayList entriesBz; - private RelativeLayout sensorDock; - private CheckBox indefiniteSamplesCheckBox; - private EditText samplesEditBox; - private SeekBar timeGapSeekbar; - private TextView timeGapLabel; - private ImageButton playPauseButton; - private boolean play; - private boolean runIndefinitely; - private int timeGap; + + private LineChart mChart; + private TextView tvSensorHMC5883Lbx; + private TextView tvSensorHMC5883Lby; + private TextView tvSensorHMC5883Lbz; @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sensor_hmc5883l); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.hmc5883l); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } - sensorDock = findViewById(R.id.sensor_control_dock_layout); - indefiniteSamplesCheckBox = findViewById(R.id.checkBox_samples_sensor); - samplesEditBox = findViewById(R.id.editBox_samples_sensors); - timeGapSeekbar = findViewById(R.id.seekBar_timegap_sensor); - timeGapLabel = findViewById(R.id.tv_timegap_label); - playPauseButton = findViewById(R.id.imageButton_play_pause_sensor); - setSensorDock(); - sensorDock.setVisibility(View.VISIBLE); - - scienceLab = ScienceLabCommon.scienceLab; - I2C i2c = scienceLab.i2c; + I2C i2c = getScienceLab().i2c; try { - sensorHMC5883L = new HMC5883L(i2c, scienceLab); + sensorHMC5883L = new HMC5883L(i2c, getScienceLab()); } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Sensor initialization failed.", e); } - entriesBx = new ArrayList<>(); - entriesBy = new ArrayList<>(); - entriesBz = new ArrayList<>(); - sensorDock.setVisibility(View.VISIBLE); - - Runnable runnable = new Runnable() { - @Override - public void run() { - while (true) { - if (scienceLab.isConnected() && shouldPlay()) { - sensorDataFetch = new SensorHMC5883L.SensorDataFetch(); - sensorDataFetch.execute(); - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - } - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - try { - Thread.sleep(timeGap); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - }; - new Thread(runnable).start(); + sensorDataFetch = new SensorDataFetch(); tvSensorHMC5883Lbx = findViewById(R.id.tv_sensor_hmc5883l_bx); tvSensorHMC5883Lby = findViewById(R.id.tv_sensor_hmc5883l_by); @@ -168,115 +98,66 @@ public void run() { y.setLabelCount(10); y2.setDrawGridLines(false); - } - private boolean shouldPlay() { - if (play) { - if (indefiniteSamplesCheckBox.isChecked()) - return true; - else if (counter >= 0) { - counter--; - return true; - } else { - play = false; - return false; - } + if (savedInstanceState == null) { + entriesBx = new ArrayList<>(); + entriesBy = new ArrayList<>(); + entriesBz = new ArrayList<>(); } else { - return false; - } - } + tvSensorHMC5883Lbx.setText(savedInstanceState.getString(KEY_VALUE_BX)); + tvSensorHMC5883Lby.setText(savedInstanceState.getString(KEY_VALUE_BY)); + tvSensorHMC5883Lbz.setText(savedInstanceState.getString(KEY_VALUE_BZ)); - private void setSensorDock() { - play = false; - runIndefinitely = true; - timeGap = 100; - final int step = 1; - final int max = 1000; - final int min = 100; - - playPauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (play && scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else if (!scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else { - playPauseButton.setImageResource(R.drawable.circle_pause_button); - play = true; - if (!indefiniteSamplesCheckBox.isChecked()) { - counter = Integer.parseInt(samplesEditBox.getText().toString()); - } - } - } - }); - sensorDock.setVisibility(View.VISIBLE); - - indefiniteSamplesCheckBox.setChecked(true); - samplesEditBox.setEnabled(false); - indefiniteSamplesCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - runIndefinitely = true; - samplesEditBox.setEnabled(false); - } else { - runIndefinitely = false; - samplesEditBox.setEnabled(true); - } - } - }); - - timeGapSeekbar.setMax((max - min) / step); - timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - timeGap = min + (progress * step); - timeGapLabel.setText(timeGap + "ms"); - } + entriesBx = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_BX); + entriesBy = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_BY); + entriesBz = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_BZ); - @Override - public void onStartTrackingTouch(SeekBar seekBar) { + sensorDataFetch.updateUi(); + } + } - } + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); - @Override - public void onStopTrackingTouch(SeekBar seekBar) { + outState.putString(KEY_VALUE_BX, tvSensorHMC5883Lbx.getText().toString()); + outState.putString(KEY_VALUE_BY, tvSensorHMC5883Lby.getText().toString()); + outState.putString(KEY_VALUE_BZ, tvSensorHMC5883Lbz.getText().toString()); - } - }); + outState.putParcelableArrayList(KEY_ENTRIES_BX, entriesBx); + outState.putParcelableArrayList(KEY_ENTRIES_BY, entriesBy); + outState.putParcelableArrayList(KEY_ENTRIES_BZ, entriesBz); } - private class SensorDataFetch extends AsyncTask { + private class SensorDataFetch extends AbstractSensorActivity.SensorDataFetch { - private ArrayList dataHMC5883L = new ArrayList<>(); - private long timeElapsed; + private List dataHMC5883L = new ArrayList<>(); + /* Initialization required if updateUi is executed before getSensorData */ + private float timeElapsed = getTimeElapsed(); @Override - protected Void doInBackground(Void... params) { + public void getSensorData() { try { if (sensorHMC5883L != null) { dataHMC5883L = sensorHMC5883L.getRaw(); } } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error getting sensor data.", e); } - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; - entriesBx.add(new Entry((float) timeElapsed, dataHMC5883L.get(0).floatValue())); - entriesBy.add(new Entry((float) timeElapsed, dataHMC5883L.get(1).floatValue())); - entriesBz.add(new Entry((float) timeElapsed, dataHMC5883L.get(2).floatValue())); - return null; + timeElapsed = getTimeElapsed(); + entriesBx.add(new Entry(timeElapsed, dataHMC5883L.get(0).floatValue())); + entriesBy.add(new Entry(timeElapsed, dataHMC5883L.get(1).floatValue())); + entriesBz.add(new Entry(timeElapsed, dataHMC5883L.get(2).floatValue())); } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); + public void updateUi() { - tvSensorHMC5883Lbx.setText(DataFormatter.formatDouble(dataHMC5883L.get(0), DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorHMC5883Lby.setText(DataFormatter.formatDouble(dataHMC5883L.get(1), DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorHMC5883Lbz.setText(DataFormatter.formatDouble(dataHMC5883L.get(2), DataFormatter.HIGH_PRECISION_FORMAT)); + if (isSensorDataAcquired()) { + tvSensorHMC5883Lbx.setText(DataFormatter.formatDouble(dataHMC5883L.get(0), DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorHMC5883Lby.setText(DataFormatter.formatDouble(dataHMC5883L.get(1), DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorHMC5883Lbz.setText(DataFormatter.formatDouble(dataHMC5883L.get(2), DataFormatter.HIGH_PRECISION_FORMAT)); + } LineDataSet dataset1 = new LineDataSet(entriesBx, getString(R.string.bx)); LineDataSet dataSet2 = new LineDataSet(entriesBy, getString(R.string.by)); @@ -299,25 +180,22 @@ protected void onPostExecute(Void aVoid) { mChart.setData(data); mChart.notifyDataSetChanged(); mChart.setVisibleXRangeMaximum(10); - mChart.moveViewToX(data.getEntryCount()); - mChart.invalidate(); - - samplesEditBox.setText(String.valueOf(counter)); - if (counter == 0 && !runIndefinitely) { - play = false; - playPauseButton.setImageResource(R.drawable.circle_play_button); - } - synchronized (lock) { - lock.notify(); - } + mChart.moveViewToX(timeElapsed); } } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; + protected AbstractSensorActivity.SensorDataFetch getSensorDataFetch() { + return sensorDataFetch; + } + + @Override + protected int getLayoutResId() { + return R.layout.sensor_hmc5883l; + } + + @Override + protected int getTitleResId() { + return R.string.hmc5883l; } } diff --git a/app/src/main/java/io/pslab/sensors/SensorMLX90614.java b/app/src/main/java/io/pslab/sensors/SensorMLX90614.java index fef015cc9..3fe9ef0f6 100644 --- a/app/src/main/java/io/pslab/sensors/SensorMLX90614.java +++ b/app/src/main/java/io/pslab/sensors/SensorMLX90614.java @@ -3,25 +3,18 @@ import android.annotation.SuppressLint; import android.content.SharedPreferences; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; +import android.util.Log; import android.view.LayoutInflater; -import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.ImageButton; import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.SeekBar; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.Legend; @@ -36,106 +29,46 @@ import io.pslab.DataFormatter; import io.pslab.R; -import io.pslab.communication.ScienceLab; import io.pslab.communication.peripherals.I2C; import io.pslab.communication.sensors.MLX90614; -import io.pslab.others.ScienceLabCommon; -public class SensorMLX90614 extends AppCompatActivity { +public class SensorMLX90614 extends AbstractSensorActivity { + private static final String TAG = SensorMLX90614.class.getSimpleName(); + + private static final String KEY_ENTRIES_OBJ_TEMP = TAG + "_entries_object_temperature"; + private static final String KEY_ENTRIES_AMB_TEMP = TAG + "_entries_ambient_temperature"; + private static final String KEY_VALUE_OBJ_TEMP = TAG + "_value_object_temperature"; + private static final String KEY_VALUE_AMB_TEMP = TAG + "_value_ambient_temperature"; private static final String PREF_NAME = "SensorMLX90614"; private static final String KEY = "SensorMLX90614Key"; - private static int counter; - private final Object lock = new Object(); - private ScienceLab scienceLab; - private SensorMLX90614.SensorDataFetch sensorDataFetch; - private TextView tvSensorMLX90614ObjectTemp; - private TextView tvSensorMLX90614AmbientTemp; + private SensorDataFetch sensorDataFetch; private MLX90614 sensorMLX90614; - private LineChart mChartObjectTemperature; - private LineChart mChartAmbientTemperature; - private long startTime; - private int flag; + private ArrayList entriesObjectTemperature; private ArrayList entriesAmbientTemperature; - private RelativeLayout sensorDock; - private CheckBox indefiniteSamplesCheckBox; - private EditText samplesEditBox; - private SeekBar timeGapSeekbar; - private TextView timeGapLabel; - private ImageButton playPauseButton; - private boolean play; - private boolean runIndefinitely; - private int timeGap; + + private LineChart mChartObjectTemperature; + private LineChart mChartAmbientTemperature; + private TextView tvSensorMLX90614ObjectTemp; + private TextView tvSensorMLX90614AmbientTemp; @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sensor_mlx90614); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.mlx90614); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } howToConnectDialog(getString(R.string.ir_thermometer), getString(R.string.ir_thermometer_intro), R.drawable.mlx90614_schematic, getString(R.string.ir_thermometer_desc)); - sensorDock = findViewById(R.id.sensor_control_dock_layout); - indefiniteSamplesCheckBox = findViewById(R.id.checkBox_samples_sensor); - samplesEditBox = findViewById(R.id.editBox_samples_sensors); - timeGapSeekbar = findViewById(R.id.seekBar_timegap_sensor); - timeGapLabel = findViewById(R.id.tv_timegap_label); - playPauseButton = findViewById(R.id.imageButton_play_pause_sensor); - setSensorDock(); - sensorDock.setVisibility(View.VISIBLE); - - scienceLab = ScienceLabCommon.scienceLab; - I2C i2c = scienceLab.i2c; + I2C i2c = getScienceLab().i2c; try { sensorMLX90614 = new MLX90614(i2c); } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Sensor initialization failed.", e); } - entriesObjectTemperature = new ArrayList<>(); - entriesAmbientTemperature = new ArrayList<>(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - while (true) { - if (scienceLab.isConnected() && shouldPlay()) { - sensorDataFetch = new SensorMLX90614.SensorDataFetch(); - sensorDataFetch.execute(); - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - } - - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - try { - Thread.sleep(timeGap); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - }; - new Thread(runnable).start(); + sensorDataFetch = new SensorDataFetch(); tvSensorMLX90614ObjectTemp = findViewById(R.id.tv_sensor_mlx90614_object_temp); tvSensorMLX90614AmbientTemp = findViewById(R.id.tv_sensor_mlx90614_ambient_temp); @@ -210,85 +143,30 @@ public void run() { yAmbientTemperature.setLabelCount(10); yAmbientTemperature2.setDrawGridLines(false); - } - private boolean shouldPlay() { - if (play) { - if (indefiniteSamplesCheckBox.isChecked()) - return true; - else if (counter >= 0) { - counter--; - return true; - } else { - play = false; - return false; - } + if (savedInstanceState == null) { + entriesObjectTemperature = new ArrayList<>(); + entriesAmbientTemperature = new ArrayList<>(); } else { - return false; - } - } + tvSensorMLX90614ObjectTemp.setText(savedInstanceState.getString(KEY_VALUE_OBJ_TEMP)); + tvSensorMLX90614AmbientTemp.setText(savedInstanceState.getString(KEY_VALUE_AMB_TEMP)); - private void setSensorDock() { - play = false; - runIndefinitely = true; - timeGap = 100; - final int step = 1; - final int max = 1000; - final int min = 100; - - playPauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (play && scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else if (!scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else { - playPauseButton.setImageResource(R.drawable.circle_pause_button); - play = true; - if (!indefiniteSamplesCheckBox.isChecked()) { - counter = Integer.parseInt(samplesEditBox.getText().toString()); - } - } - } - }); - sensorDock.setVisibility(View.VISIBLE); - - indefiniteSamplesCheckBox.setChecked(true); - samplesEditBox.setEnabled(false); - indefiniteSamplesCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - runIndefinitely = true; - samplesEditBox.setEnabled(false); - } else { - runIndefinitely = false; - samplesEditBox.setEnabled(true); - } - } - }); - - timeGapSeekbar.setMax((max - min) / step); - timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - timeGap = min + (progress * step); - timeGapLabel.setText(timeGap + "ms"); - } + entriesObjectTemperature = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_OBJ_TEMP); + entriesAmbientTemperature = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_AMB_TEMP); - @Override - public void onStartTrackingTouch(SeekBar seekBar) { + sensorDataFetch.updateUi(); + } + } - } + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); - @Override - public void onStopTrackingTouch(SeekBar seekBar) { + outState.putString(KEY_VALUE_OBJ_TEMP, tvSensorMLX90614ObjectTemp.getText().toString()); + outState.putString(KEY_VALUE_AMB_TEMP, tvSensorMLX90614AmbientTemp.getText().toString()); - } - }); + outState.putParcelableArrayList(KEY_ENTRIES_OBJ_TEMP, entriesObjectTemperature); + outState.putParcelableArrayList(KEY_ENTRIES_AMB_TEMP, entriesAmbientTemperature); } @SuppressLint("ResourceType") @@ -311,53 +189,52 @@ public void howToConnectDialog(String title, String intro, int imageID, String d final SharedPreferences sharedPreferences = this.getSharedPreferences(PREF_NAME, MODE_PRIVATE); final AlertDialog dialog = builder.create(); - Boolean skipDialog = sharedPreferences.getBoolean(KEY, false); - okButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (doNotShowDialog.isChecked()) { - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putBoolean(KEY, true); - editor.apply(); - } - dialog.dismiss(); + boolean skipDialog = sharedPreferences.getBoolean(KEY, false); + okButton.setOnClickListener(v -> { + if (doNotShowDialog.isChecked()) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(KEY, true); + editor.apply(); } + dialog.dismiss(); }); if (!skipDialog) { dialog.show(); } } catch (Exception e) { - e.printStackTrace(); + Log.e(TAG, "Error showing dialog.", e); } } - private class SensorDataFetch extends AsyncTask { + private class SensorDataFetch extends AbstractSensorActivity.SensorDataFetch { private Double dataMLX90614ObjectTemp; private Double dataMLX90614AmbientTemp; - private long timeElapsed; + /* Initialization required if updateUi is executed before getSensorData */ + private float timeElapsed = getTimeElapsed(); @Override - protected Void doInBackground(Void... params) { + public void getSensorData() { try { if (sensorMLX90614 != null) { dataMLX90614ObjectTemp = sensorMLX90614.getObjectTemperature(); dataMLX90614AmbientTemp = sensorMLX90614.getAmbientTemperature(); } } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error getting sensor data.", e); } - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; - entriesObjectTemperature.add(new Entry((float) timeElapsed, dataMLX90614ObjectTemp.floatValue())); - entriesAmbientTemperature.add(new Entry((float) timeElapsed, dataMLX90614AmbientTemp.floatValue())); - return null; + timeElapsed = getTimeElapsed(); + entriesObjectTemperature.add(new Entry(timeElapsed, dataMLX90614ObjectTemp.floatValue())); + entriesAmbientTemperature.add(new Entry(timeElapsed, dataMLX90614AmbientTemp.floatValue())); } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - tvSensorMLX90614ObjectTemp.setText(DataFormatter.formatDouble(dataMLX90614ObjectTemp, DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMLX90614AmbientTemp.setText(DataFormatter.formatDouble(dataMLX90614AmbientTemp, DataFormatter.HIGH_PRECISION_FORMAT)); + public void updateUi() { + + if (isSensorDataAcquired()) { + tvSensorMLX90614ObjectTemp.setText(DataFormatter.formatDouble(dataMLX90614ObjectTemp, DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMLX90614AmbientTemp.setText(DataFormatter.formatDouble(dataMLX90614AmbientTemp, DataFormatter.HIGH_PRECISION_FORMAT)); + } LineDataSet dataSet1 = new LineDataSet(entriesObjectTemperature, getString(R.string.object_temp)); LineDataSet dataSet2 = new LineDataSet(entriesAmbientTemperature, getString(R.string.ambient_temp)); @@ -369,31 +246,28 @@ protected void onPostExecute(Void aVoid) { mChartObjectTemperature.setData(data1); mChartObjectTemperature.notifyDataSetChanged(); mChartObjectTemperature.setVisibleXRangeMaximum(10); - mChartObjectTemperature.moveViewToX(data1.getEntryCount()); - mChartObjectTemperature.invalidate(); + mChartObjectTemperature.moveViewToX(timeElapsed); LineData data2 = new LineData(dataSet2); mChartAmbientTemperature.setData(data2); mChartAmbientTemperature.notifyDataSetChanged(); mChartAmbientTemperature.setVisibleXRangeMaximum(10); - mChartAmbientTemperature.moveViewToX(data2.getEntryCount()); - mChartAmbientTemperature.invalidate(); - samplesEditBox.setText(String.valueOf(counter)); - if (counter == 0 && !runIndefinitely) { - play = false; - playPauseButton.setImageResource(R.drawable.circle_play_button); - } - synchronized (lock) { - lock.notify(); - } + mChartAmbientTemperature.moveViewToX(timeElapsed); } } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; + protected AbstractSensorActivity.SensorDataFetch getSensorDataFetch() { + return sensorDataFetch; + } + + @Override + protected int getLayoutResId() { + return R.layout.sensor_mlx90614; + } + + @Override + protected int getTitleResId() { + return R.string.mlx90614; } } diff --git a/app/src/main/java/io/pslab/sensors/SensorMPU6050.java b/app/src/main/java/io/pslab/sensors/SensorMPU6050.java index 0a2518ddd..cfa3a1241 100644 --- a/app/src/main/java/io/pslab/sensors/SensorMPU6050.java +++ b/app/src/main/java/io/pslab/sensors/SensorMPU6050.java @@ -1,22 +1,13 @@ package io.pslab.sensors; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; -import android.view.MenuItem; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.RelativeLayout; -import android.widget.SeekBar; +import android.util.Log; import android.widget.Spinner; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.Legend; @@ -33,117 +24,66 @@ import io.pslab.DataFormatter; import io.pslab.R; -import io.pslab.communication.ScienceLab; import io.pslab.communication.peripherals.I2C; import io.pslab.communication.sensors.MPU6050; -import io.pslab.others.ScienceLabCommon; -/** - * Created by Harsh on 6/6/18. - */ +public class SensorMPU6050 extends AbstractSensorActivity { + private static final String TAG = SensorMPU6050.class.getSimpleName(); + + private static final String KEY_ENTRIES_AX = TAG + "_entries_ax"; + private static final String KEY_ENTRIES_AY = TAG + "_entries_ay"; + private static final String KEY_ENTRIES_AZ = TAG + "_entries_az"; + private static final String KEY_ENTRIES_GX = TAG + "_entries_gx"; + private static final String KEY_ENTRIES_GY = TAG + "_entries_gy"; + private static final String KEY_ENTRIES_GZ = TAG + "_entries_gz"; + private static final String KEY_VALUE_AX = TAG + "_value_ax"; + private static final String KEY_VALUE_AY = TAG + "_value_ay"; + private static final String KEY_VALUE_AZ = TAG + "_value_az"; + private static final String KEY_VALUE_GX = TAG + "_value_gx"; + private static final String KEY_VALUE_GY = TAG + "_value_gy"; + private static final String KEY_VALUE_GZ = TAG + "_value_gz"; + private static final String KEY_VALUE_TEMP = TAG + "_value_temp"; + private static final String KEY_POS_1 = TAG + "_pos_1"; + private static final String KEY_POS_2 = TAG + "_pos_2"; + private static final String KEY_POS_3 = TAG + "_pos_3"; + private static final String KEY_POS_4 = TAG + "_pos_4"; -public class SensorMPU6050 extends AppCompatActivity { - private static int counter; - private final Object lock = new Object(); - private ScienceLab scienceLab; private SensorMPU6050.SensorDataFetch sensorDataFetch; - private TextView tvSensorMPU6050ax; - private TextView tvSensorMPU6050ay; - private TextView tvSensorMPU6050az; - private TextView tvSensorMPU6050gx; - private TextView tvSensorMPU6050gy; - private TextView tvSensorMPU6050gz; - private TextView tvSensorMPU6050temp; private MPU6050 sensorMPU6050; - private LineChart mChartAcceleration; - private LineChart mChartGyroscope; - private long startTime; - private int flag; + private ArrayList entriesAx; private ArrayList entriesAy; private ArrayList entriesAz; private ArrayList entriesGx; private ArrayList entriesGy; private ArrayList entriesGz; - private RelativeLayout sensorDock; - private CheckBox indefiniteSamplesCheckBox; - private EditText samplesEditBox; - private SeekBar timeGapSeekbar; - private TextView timeGapLabel; - private ImageButton playPauseButton; - private boolean play; - private boolean runIndefinitely; - private int timeGap; + + private LineChart mChartAcceleration; + private LineChart mChartGyroscope; + private TextView tvSensorMPU6050ax; + private TextView tvSensorMPU6050ay; + private TextView tvSensorMPU6050az; + private TextView tvSensorMPU6050gx; + private TextView tvSensorMPU6050gy; + private TextView tvSensorMPU6050gz; + private TextView tvSensorMPU6050temp; + private Spinner spinnerSensorMPU60501; + private Spinner spinnerSensorMPU60502; + private Spinner spinnerSensorMPU60503; + private Spinner spinnerSensorMPU60504; @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sensor_mpu6050); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.mpu6050); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } - sensorDock = findViewById(R.id.sensor_control_dock_layout); - indefiniteSamplesCheckBox = findViewById(R.id.checkBox_samples_sensor); - samplesEditBox = findViewById(R.id.editBox_samples_sensors); - timeGapSeekbar = findViewById(R.id.seekBar_timegap_sensor); - timeGapLabel = findViewById(R.id.tv_timegap_label); - playPauseButton = findViewById(R.id.imageButton_play_pause_sensor); - setSensorDock(); - sensorDock.setVisibility(View.VISIBLE); - - scienceLab = ScienceLabCommon.scienceLab; - I2C i2c = scienceLab.i2c; + I2C i2c = getScienceLab().i2c; try { - sensorMPU6050 = new MPU6050(i2c, scienceLab); + sensorMPU6050 = new MPU6050(i2c, getScienceLab()); } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Sensor initialization failed.", e); } - entriesAx = new ArrayList<>(); - entriesAy = new ArrayList<>(); - entriesAz = new ArrayList<>(); - entriesGx = new ArrayList<>(); - entriesGy = new ArrayList<>(); - entriesGz = new ArrayList<>(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - while (true) { - if (scienceLab.isConnected() && shouldPlay()) { - sensorDataFetch = new SensorMPU6050.SensorDataFetch(); - sensorDataFetch.execute(); - - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - } - - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - try { - Thread.sleep(timeGap); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - }; - new Thread(runnable).start(); + sensorDataFetch = new SensorDataFetch(); tvSensorMPU6050ax = findViewById(R.id.tv_sensor_mpu6050_ax); tvSensorMPU6050ay = findViewById(R.id.tv_sensor_mpu6050_ay); @@ -153,10 +93,10 @@ public void run() { tvSensorMPU6050gz = findViewById(R.id.tv_sensor_mpu6050_gz); tvSensorMPU6050temp = findViewById(R.id.tv_sensor_mpu6050_temp); - Spinner spinnerSensorMPU60501 = findViewById(R.id.spinner_sensor_mpu6050_1); - Spinner spinnerSensorMPU60502 = findViewById(R.id.spinner_sensor_mpu6050_2); - Spinner spinnerSensorMPU60503 = findViewById(R.id.spinner_sensor_mpu6050_3); - Spinner spinnerSensorMPU60504 = findViewById(R.id.spinner_sensor_mpu6050_4); + spinnerSensorMPU60501 = findViewById(R.id.spinner_sensor_mpu6050_1); + spinnerSensorMPU60502 = findViewById(R.id.spinner_sensor_mpu6050_2); + spinnerSensorMPU60503 = findViewById(R.id.spinner_sensor_mpu6050_3); + spinnerSensorMPU60504 = findViewById(R.id.spinner_sensor_mpu6050_4); mChartAcceleration = findViewById(R.id.chart_sensor_mpu6050_accelerometer); mChartGyroscope = findViewById(R.id.chart_sensor_mpu6050_gyroscope); @@ -230,138 +170,115 @@ public void run() { yGyroscope2.setDrawGridLines(false); try { - if (sensorMPU6050 != null && scienceLab.isConnected()) { + if (sensorMPU6050 != null && getScienceLab().isConnected()) { sensorMPU6050.setAccelerationRange(Integer.parseInt(spinnerSensorMPU60502.getSelectedItem().toString())); } } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error setting range.", e); } try { - if (sensorMPU6050 != null && scienceLab.isConnected()) { + if (sensorMPU6050 != null && getScienceLab().isConnected()) { sensorMPU6050.setGyroRange(Integer.parseInt(spinnerSensorMPU60501.getSelectedItem().toString())); } } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error setting range.", e); } - } - - private boolean shouldPlay() { - if (play && scienceLab.isConnected()) { - if (indefiniteSamplesCheckBox.isChecked()) - return true; - else if (counter >= 0) { - counter--; - return true; - } else { - play = false; - return false; - } + if (savedInstanceState == null) { + entriesAx = new ArrayList<>(); + entriesAy = new ArrayList<>(); + entriesAz = new ArrayList<>(); + entriesGx = new ArrayList<>(); + entriesGy = new ArrayList<>(); + entriesGz = new ArrayList<>(); } else { - return false; + spinnerSensorMPU60501.setSelection(savedInstanceState.getInt(KEY_POS_1)); + spinnerSensorMPU60502.setSelection(savedInstanceState.getInt(KEY_POS_2)); + spinnerSensorMPU60503.setSelection(savedInstanceState.getInt(KEY_POS_3)); + spinnerSensorMPU60504.setSelection(savedInstanceState.getInt(KEY_POS_4)); + + tvSensorMPU6050ax.setText(savedInstanceState.getString(KEY_VALUE_AX)); + tvSensorMPU6050ay.setText(savedInstanceState.getString(KEY_VALUE_AY)); + tvSensorMPU6050az.setText(savedInstanceState.getString(KEY_VALUE_AZ)); + tvSensorMPU6050gx.setText(savedInstanceState.getString(KEY_VALUE_GX)); + tvSensorMPU6050gy.setText(savedInstanceState.getString(KEY_VALUE_GY)); + tvSensorMPU6050gz.setText(savedInstanceState.getString(KEY_VALUE_GZ)); + tvSensorMPU6050temp.setText(savedInstanceState.getString(KEY_VALUE_TEMP)); + + entriesAx = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_AX); + entriesAy = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_AY); + entriesAz = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_AZ); + entriesGx = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_GX); + entriesGy = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_GY); + entriesGz = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_GZ); + + sensorDataFetch.updateUi(); } } - private void setSensorDock() { - play = false; - runIndefinitely = true; - timeGap = 100; - final int step = 1; - final int max = 1000; - final int min = 100; - - playPauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (play && scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else if (!scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else { - playPauseButton.setImageResource(R.drawable.circle_pause_button); - play = true; - if (!indefiniteSamplesCheckBox.isChecked()) { - counter = Integer.parseInt(samplesEditBox.getText().toString()); - } - } - } - }); - sensorDock.setVisibility(View.VISIBLE); - - indefiniteSamplesCheckBox.setChecked(true); - samplesEditBox.setEnabled(false); - indefiniteSamplesCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - runIndefinitely = true; - samplesEditBox.setEnabled(false); - } else { - runIndefinitely = false; - samplesEditBox.setEnabled(true); - } - } - }); - - timeGapSeekbar.setMax((max - min) / step); - timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - timeGap = min + (progress * step); - timeGapLabel.setText(timeGap + "ms"); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - - } - }); + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putInt(KEY_POS_1, spinnerSensorMPU60501.getSelectedItemPosition()); + outState.putInt(KEY_POS_2, spinnerSensorMPU60502.getSelectedItemPosition()); + outState.putInt(KEY_POS_3, spinnerSensorMPU60503.getSelectedItemPosition()); + outState.putInt(KEY_POS_4, spinnerSensorMPU60504.getSelectedItemPosition()); + + outState.putString(KEY_VALUE_AX, tvSensorMPU6050ax.getText().toString()); + outState.putString(KEY_VALUE_AY, tvSensorMPU6050ay.getText().toString()); + outState.putString(KEY_VALUE_AZ, tvSensorMPU6050az.getText().toString()); + outState.putString(KEY_VALUE_GX, tvSensorMPU6050gx.getText().toString()); + outState.putString(KEY_VALUE_GY, tvSensorMPU6050gy.getText().toString()); + outState.putString(KEY_VALUE_GZ, tvSensorMPU6050gz.getText().toString()); + outState.putString(KEY_VALUE_TEMP, tvSensorMPU6050temp.getText().toString()); + + outState.putParcelableArrayList(KEY_ENTRIES_AX, entriesAx); + outState.putParcelableArrayList(KEY_ENTRIES_AY, entriesAy); + outState.putParcelableArrayList(KEY_ENTRIES_AZ, entriesAz); + outState.putParcelableArrayList(KEY_ENTRIES_GX, entriesGx); + outState.putParcelableArrayList(KEY_ENTRIES_GY, entriesGy); + outState.putParcelableArrayList(KEY_ENTRIES_GZ, entriesGz); } - private class SensorDataFetch extends AsyncTask { + private class SensorDataFetch extends AbstractSensorActivity.SensorDataFetch { - private ArrayList dataMPU6050 = new ArrayList<>(); - private long timeElapsed; + private List dataMPU6050 = new ArrayList<>(); + /* Initialization required if updateUi is executed before getSensorData */ + private float timeElapsed = getTimeElapsed(); @Override - protected Void doInBackground(Void... params) { + public void getSensorData() { try { dataMPU6050 = sensorMPU6050.getRaw(); } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error getting sensor data.", e); } - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; - - entriesAx.add(new Entry((float) timeElapsed, dataMPU6050.get(0).floatValue())); - entriesAy.add(new Entry((float) timeElapsed, dataMPU6050.get(1).floatValue())); - entriesAz.add(new Entry((float) timeElapsed, dataMPU6050.get(2).floatValue())); + timeElapsed = getTimeElapsed(); - entriesGx.add(new Entry((float) timeElapsed, dataMPU6050.get(4).floatValue())); - entriesGy.add(new Entry((float) timeElapsed, dataMPU6050.get(5).floatValue())); - entriesGz.add(new Entry((float) timeElapsed, dataMPU6050.get(6).floatValue())); + entriesAx.add(new Entry(timeElapsed, dataMPU6050.get(0).floatValue())); + entriesAy.add(new Entry(timeElapsed, dataMPU6050.get(1).floatValue())); + entriesAz.add(new Entry(timeElapsed, dataMPU6050.get(2).floatValue())); - return null; + entriesGx.add(new Entry(timeElapsed, dataMPU6050.get(4).floatValue())); + entriesGy.add(new Entry(timeElapsed, dataMPU6050.get(5).floatValue())); + entriesGz.add(new Entry(timeElapsed, dataMPU6050.get(6).floatValue())); } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - tvSensorMPU6050ax.setText(DataFormatter.formatDouble(dataMPU6050.get(0), DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU6050ay.setText(DataFormatter.formatDouble(dataMPU6050.get(1), DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU6050az.setText(DataFormatter.formatDouble(dataMPU6050.get(2), DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU6050gx.setText(DataFormatter.formatDouble(dataMPU6050.get(4), DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU6050gy.setText(DataFormatter.formatDouble(dataMPU6050.get(5), DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU6050gz.setText(DataFormatter.formatDouble(dataMPU6050.get(6), DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU6050temp.setText(DataFormatter.formatDouble(dataMPU6050.get(3), DataFormatter.HIGH_PRECISION_FORMAT)); + public void updateUi() { + + if (isSensorDataAcquired()) { + tvSensorMPU6050ax.setText(DataFormatter.formatDouble(dataMPU6050.get(0), DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU6050ay.setText(DataFormatter.formatDouble(dataMPU6050.get(1), DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU6050az.setText(DataFormatter.formatDouble(dataMPU6050.get(2), DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU6050gx.setText(DataFormatter.formatDouble(dataMPU6050.get(4), DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU6050gy.setText(DataFormatter.formatDouble(dataMPU6050.get(5), DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU6050gz.setText(DataFormatter.formatDouble(dataMPU6050.get(6), DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU6050temp.setText(DataFormatter.formatDouble(dataMPU6050.get(3), DataFormatter.HIGH_PRECISION_FORMAT)); + } LineDataSet dataset1 = new LineDataSet(entriesAx, getString(R.string.ax)); LineDataSet dataSet2 = new LineDataSet(entriesAy, getString(R.string.ay)); @@ -394,31 +311,28 @@ protected void onPostExecute(Void aVoid) { mChartAcceleration.setData(data); mChartAcceleration.notifyDataSetChanged(); mChartAcceleration.setVisibleXRangeMaximum(10); - mChartAcceleration.moveViewToX(data.getEntryCount()); - mChartAcceleration.invalidate(); + mChartAcceleration.moveViewToX(timeElapsed); LineData data2 = new LineData(dataSets2); mChartGyroscope.setData(data2); mChartGyroscope.notifyDataSetChanged(); mChartGyroscope.setVisibleXRangeMaximum(10); - mChartGyroscope.moveViewToX(data2.getEntryCount()); - mChartGyroscope.invalidate(); - samplesEditBox.setText(String.valueOf(counter)); - if (counter == 0 && !runIndefinitely) { - play = false; - playPauseButton.setImageResource(R.drawable.circle_play_button); - } - synchronized (lock) { - lock.notify(); - } + mChartGyroscope.moveViewToX(timeElapsed); } } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; + protected AbstractSensorActivity.SensorDataFetch getSensorDataFetch() { + return sensorDataFetch; + } + + @Override + protected int getLayoutResId() { + return R.layout.sensor_mpu6050; + } + + @Override + protected int getTitleResId() { + return R.string.mpu6050; } } diff --git a/app/src/main/java/io/pslab/sensors/SensorMPU925X.java b/app/src/main/java/io/pslab/sensors/SensorMPU925X.java index 8a81203d4..79a784728 100644 --- a/app/src/main/java/io/pslab/sensors/SensorMPU925X.java +++ b/app/src/main/java/io/pslab/sensors/SensorMPU925X.java @@ -1,22 +1,13 @@ package io.pslab.sensors; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; -import android.view.MenuItem; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.RelativeLayout; -import android.widget.SeekBar; +import android.util.Log; import android.widget.Spinner; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.Legend; @@ -33,20 +24,42 @@ import io.pslab.DataFormatter; import io.pslab.R; -import io.pslab.communication.ScienceLab; import io.pslab.communication.peripherals.I2C; import io.pslab.communication.sensors.MPU925x; -import io.pslab.others.ScienceLabCommon; -/** - * Created by Harsh on 6/6/18. - */ +public class SensorMPU925X extends AbstractSensorActivity { + private static final String TAG = SensorMPU925X.class.getSimpleName(); + + private static final String KEY_ENTRIES_AX = TAG + "_entries_ax"; + private static final String KEY_ENTRIES_AY = TAG + "_entries_ay"; + private static final String KEY_ENTRIES_AZ = TAG + "_entries_az"; + private static final String KEY_ENTRIES_GX = TAG + "_entries_gx"; + private static final String KEY_ENTRIES_GY = TAG + "_entries_gy"; + private static final String KEY_ENTRIES_GZ = TAG + "_entries_gz"; + private static final String KEY_VALUE_AX = TAG + "_value_ax"; + private static final String KEY_VALUE_AY = TAG + "_value_ay"; + private static final String KEY_VALUE_AZ = TAG + "_value_az"; + private static final String KEY_VALUE_GX = TAG + "_value_gx"; + private static final String KEY_VALUE_GY = TAG + "_value_gy"; + private static final String KEY_VALUE_GZ = TAG + "_value_gz"; + private static final String KEY_VALUE_TEMP = TAG + "_value_temp"; + private static final String KEY_POS_1 = TAG + "_pos_1"; + private static final String KEY_POS_2 = TAG + "_pos_2"; + private static final String KEY_POS_3 = TAG + "_pos_3"; + private static final String KEY_POS_4 = TAG + "_pos_4"; + + private SensorDataFetch sensorDataFetch; + private MPU925x sensorMPU925X; + + private ArrayList entriesAx; + private ArrayList entriesAy; + private ArrayList entriesAz; + private ArrayList entriesGx; + private ArrayList entriesGy; + private ArrayList entriesGz; -public class SensorMPU925X extends AppCompatActivity { - private static int counter; - private final Object lock = new Object(); - private ScienceLab scienceLab; - private SensorMPU925X.SensorDataFetch sensorDataFetch; + private LineChart mChartAcceleration; + private LineChart mChartGyroscope; private TextView tvSensorMPU925Xax; private TextView tvSensorMPU925Xay; private TextView tvSensorMPU925Xaz; @@ -54,97 +67,23 @@ public class SensorMPU925X extends AppCompatActivity { private TextView tvSensorMPU925Xgy; private TextView tvSensorMPU925Xgz; private TextView tvSensorMPU925Xtemp; - private MPU925x sensorMPU925X; - private LineChart mChartAcceleration; - private LineChart mChartGyroscope; - private long startTime; - private int flag; - private ArrayList entriesax; - private ArrayList entriesay; - private ArrayList entriesaz; - private ArrayList entriesgx; - private ArrayList entriesgy; - private ArrayList entriesgz; - private RelativeLayout sensorDock; - private CheckBox indefiniteSamplesCheckBox; - private EditText samplesEditBox; - private SeekBar timeGapSeekbar; - private TextView timeGapLabel; - private ImageButton playPauseButton; - private boolean play; - private boolean runIndefinitely; - private int timeGap; + private Spinner spinnerSensorMPU925X1; + private Spinner spinnerSensorMPU925X2; + private Spinner spinnerSensorMPU925X3; + private Spinner spinnerSensorMPU925X4; @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sensor_mpu925x); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.mpu925x); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } - sensorDock = findViewById(R.id.sensor_control_dock_layout); - indefiniteSamplesCheckBox = findViewById(R.id.checkBox_samples_sensor); - samplesEditBox = findViewById(R.id.editBox_samples_sensors); - timeGapSeekbar = findViewById(R.id.seekBar_timegap_sensor); - timeGapLabel = findViewById(R.id.tv_timegap_label); - playPauseButton = findViewById(R.id.imageButton_play_pause_sensor); - setSensorDock(); - sensorDock.setVisibility(View.VISIBLE); - - scienceLab = ScienceLabCommon.scienceLab; - I2C i2c = scienceLab.i2c; + I2C i2c = getScienceLab().i2c; try { - if (i2c == null) throw new IOException("i2c not found"); sensorMPU925X = new MPU925x(i2c); - } catch (IOException e) { - e.printStackTrace(); + } catch (IOException | NullPointerException e) { + Log.e(TAG, "Sensor initialization failed.", e); } - entriesax = new ArrayList<>(); - entriesay = new ArrayList<>(); - entriesaz = new ArrayList<>(); - entriesgx = new ArrayList<>(); - entriesgy = new ArrayList<>(); - entriesgz = new ArrayList<>(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - while (true) { - if (scienceLab.isConnected() && shouldPlay()) { - sensorDataFetch = new SensorMPU925X.SensorDataFetch(); - sensorDataFetch.execute(); - - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - } - - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - try { - Thread.sleep(timeGap); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - }; - new Thread(runnable).start(); + sensorDataFetch = new SensorDataFetch(); tvSensorMPU925Xax = findViewById(R.id.tv_sensor_mpu925x_ax); tvSensorMPU925Xay = findViewById(R.id.tv_sensor_mpu925x_ay); @@ -154,10 +93,10 @@ public void run() { tvSensorMPU925Xgz = findViewById(R.id.tv_sensor_mpu925x_gz); tvSensorMPU925Xtemp = findViewById(R.id.tv_sensor_mpu925x_temp); - Spinner spinnerSensorMPU925X1 = findViewById(R.id.spinner_sensor_mpu925x_1); - Spinner spinnerSensorMPU925X2 = findViewById(R.id.spinner_sensor_mpu925x_2); - Spinner spinnerSensorMPU925X3 = findViewById(R.id.spinner_sensor_mpu925x_3); - Spinner spinnerSensorMPU925X4 = findViewById(R.id.spinner_sensor_mpu925x_4); + spinnerSensorMPU925X1 = findViewById(R.id.spinner_sensor_mpu925x_1); + spinnerSensorMPU925X2 = findViewById(R.id.spinner_sensor_mpu925x_2); + spinnerSensorMPU925X3 = findViewById(R.id.spinner_sensor_mpu925x_3); + spinnerSensorMPU925X4 = findViewById(R.id.spinner_sensor_mpu925x_4); mChartAcceleration = findViewById(R.id.chart_sensor_mpu925x_accelerometer); mChartGyroscope = findViewById(R.id.chart_sensor_mpu925x_gyroscope); @@ -235,7 +174,7 @@ public void run() { sensorMPU925X.setAccelRange(Integer.parseInt(spinnerSensorMPU925X2.getSelectedItem().toString())); } } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error setting range.", e); } try { @@ -243,136 +182,114 @@ public void run() { sensorMPU925X.setGyroRange(Integer.parseInt(spinnerSensorMPU925X1.getSelectedItem().toString())); } } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error setting range.", e); } - } - - private boolean shouldPlay() { - if (play) { - if (indefiniteSamplesCheckBox.isChecked()) - return true; - else if (counter >= 0) { - counter--; - return true; - } else { - play = false; - return false; - } + if (savedInstanceState == null) { + entriesAx = new ArrayList<>(); + entriesAy = new ArrayList<>(); + entriesAz = new ArrayList<>(); + entriesGx = new ArrayList<>(); + entriesGy = new ArrayList<>(); + entriesGz = new ArrayList<>(); } else { - return false; + spinnerSensorMPU925X1.setSelection(savedInstanceState.getInt(KEY_POS_1)); + spinnerSensorMPU925X2.setSelection(savedInstanceState.getInt(KEY_POS_2)); + spinnerSensorMPU925X3.setSelection(savedInstanceState.getInt(KEY_POS_3)); + spinnerSensorMPU925X4.setSelection(savedInstanceState.getInt(KEY_POS_4)); + + tvSensorMPU925Xax.setText(savedInstanceState.getString(KEY_VALUE_AX)); + tvSensorMPU925Xay.setText(savedInstanceState.getString(KEY_VALUE_AY)); + tvSensorMPU925Xaz.setText(savedInstanceState.getString(KEY_VALUE_AZ)); + tvSensorMPU925Xgx.setText(savedInstanceState.getString(KEY_VALUE_GX)); + tvSensorMPU925Xgy.setText(savedInstanceState.getString(KEY_VALUE_GY)); + tvSensorMPU925Xgz.setText(savedInstanceState.getString(KEY_VALUE_GZ)); + tvSensorMPU925Xtemp.setText(savedInstanceState.getString(KEY_VALUE_TEMP)); + + entriesAx = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_AX); + entriesAy = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_AY); + entriesAz = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_AZ); + entriesGx = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_GX); + entriesGy = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_GY); + entriesGz = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_GZ); + + sensorDataFetch.updateUi(); } } - private void setSensorDock() { - play = false; - runIndefinitely = true; - timeGap = 100; - final int step = 1; - final int max = 1000; - final int min = 100; - - playPauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (play && scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else if (!scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else { - playPauseButton.setImageResource(R.drawable.circle_pause_button); - play = true; - if (!indefiniteSamplesCheckBox.isChecked()) { - counter = Integer.parseInt(samplesEditBox.getText().toString()); - } - } - } - }); - sensorDock.setVisibility(View.VISIBLE); - - indefiniteSamplesCheckBox.setChecked(true); - samplesEditBox.setEnabled(false); - indefiniteSamplesCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - runIndefinitely = true; - samplesEditBox.setEnabled(false); - } else { - runIndefinitely = false; - samplesEditBox.setEnabled(true); - } - } - }); - - timeGapSeekbar.setMax((max - min) / step); - timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - timeGap = min + (progress * step); - timeGapLabel.setText(timeGap + "ms"); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - - } - }); + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putInt(KEY_POS_1, spinnerSensorMPU925X1.getSelectedItemPosition()); + outState.putInt(KEY_POS_2, spinnerSensorMPU925X2.getSelectedItemPosition()); + outState.putInt(KEY_POS_3, spinnerSensorMPU925X3.getSelectedItemPosition()); + outState.putInt(KEY_POS_4, spinnerSensorMPU925X4.getSelectedItemPosition()); + + outState.putString(KEY_VALUE_AX, tvSensorMPU925Xax.getText().toString()); + outState.putString(KEY_VALUE_AY, tvSensorMPU925Xay.getText().toString()); + outState.putString(KEY_VALUE_AZ, tvSensorMPU925Xaz.getText().toString()); + outState.putString(KEY_VALUE_GX, tvSensorMPU925Xgx.getText().toString()); + outState.putString(KEY_VALUE_GY, tvSensorMPU925Xgy.getText().toString()); + outState.putString(KEY_VALUE_GZ, tvSensorMPU925Xgz.getText().toString()); + outState.putString(KEY_VALUE_TEMP, tvSensorMPU925Xtemp.getText().toString()); + + outState.putParcelableArrayList(KEY_ENTRIES_AX, entriesAx); + outState.putParcelableArrayList(KEY_ENTRIES_AY, entriesAy); + outState.putParcelableArrayList(KEY_ENTRIES_AZ, entriesAz); + outState.putParcelableArrayList(KEY_ENTRIES_GX, entriesGx); + outState.putParcelableArrayList(KEY_ENTRIES_GY, entriesGy); + outState.putParcelableArrayList(KEY_ENTRIES_GZ, entriesGz); } - private class SensorDataFetch extends AsyncTask { + private class SensorDataFetch extends AbstractSensorActivity.SensorDataFetch { private double[] dataGyro, dataAccel; private double dataTemp; - private long timeElapsed; + /* Initialization required if updateUi is executed before getSensorData */ + private float timeElapsed = getTimeElapsed(); @Override - protected Void doInBackground(Void... params) { + public void getSensorData() { try { dataGyro = sensorMPU925X.getGyroscope(); dataAccel = sensorMPU925X.getAcceleration(); dataTemp = sensorMPU925X.getTemperature(); } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error getting sensor data.", e); } - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; + timeElapsed = getTimeElapsed(); - entriesax.add(new Entry((float) timeElapsed, (float) dataAccel[0])); - entriesay.add(new Entry((float) timeElapsed, (float) dataAccel[1])); - entriesaz.add(new Entry((float) timeElapsed, (float) dataAccel[2])); + entriesAx.add(new Entry(timeElapsed, (float) dataAccel[0])); + entriesAy.add(new Entry(timeElapsed, (float) dataAccel[1])); + entriesAz.add(new Entry(timeElapsed, (float) dataAccel[2])); - entriesgx.add(new Entry((float) timeElapsed, (float) dataGyro[0])); - entriesgy.add(new Entry((float) timeElapsed, (float) dataGyro[1])); - entriesgz.add(new Entry((float) timeElapsed, (float) dataGyro[2])); - - return null; + entriesGx.add(new Entry(timeElapsed, (float) dataGyro[0])); + entriesGy.add(new Entry(timeElapsed, (float) dataGyro[1])); + entriesGz.add(new Entry(timeElapsed, (float) dataGyro[2])); } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - tvSensorMPU925Xax.setText(DataFormatter.formatDouble(dataAccel[0], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU925Xay.setText(DataFormatter.formatDouble(dataAccel[1], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU925Xaz.setText(DataFormatter.formatDouble(dataAccel[2], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU925Xgx.setText(DataFormatter.formatDouble(dataGyro[0], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU925Xgy.setText(DataFormatter.formatDouble(dataGyro[1], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU925Xgz.setText(DataFormatter.formatDouble(dataGyro[2], DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorMPU925Xtemp.setText(DataFormatter.formatDouble(dataTemp, DataFormatter.HIGH_PRECISION_FORMAT)); - LineDataSet dataSet1 = new LineDataSet(entriesax, getString(R.string.ax)); - LineDataSet dataSet2 = new LineDataSet(entriesay, getString(R.string.ay)); - LineDataSet dataSet3 = new LineDataSet(entriesaz, getString(R.string.az)); + public void updateUi() { + + if (isSensorDataAcquired()) { + tvSensorMPU925Xax.setText(DataFormatter.formatDouble(dataAccel[0], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU925Xay.setText(DataFormatter.formatDouble(dataAccel[1], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU925Xaz.setText(DataFormatter.formatDouble(dataAccel[2], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU925Xgx.setText(DataFormatter.formatDouble(dataGyro[0], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU925Xgy.setText(DataFormatter.formatDouble(dataGyro[1], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU925Xgz.setText(DataFormatter.formatDouble(dataGyro[2], DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorMPU925Xtemp.setText(DataFormatter.formatDouble(dataTemp, DataFormatter.HIGH_PRECISION_FORMAT)); + } + + LineDataSet dataSet1 = new LineDataSet(entriesAx, getString(R.string.ax)); + LineDataSet dataSet2 = new LineDataSet(entriesAy, getString(R.string.ay)); + LineDataSet dataSet3 = new LineDataSet(entriesAz, getString(R.string.az)); - LineDataSet dataSet4 = new LineDataSet(entriesgx, getString(R.string.gx)); - LineDataSet dataSet5 = new LineDataSet(entriesgy, getString(R.string.gy)); - LineDataSet dataSet6 = new LineDataSet(entriesgz, getString(R.string.gz)); + LineDataSet dataSet4 = new LineDataSet(entriesGx, getString(R.string.gx)); + LineDataSet dataSet5 = new LineDataSet(entriesGy, getString(R.string.gy)); + LineDataSet dataSet6 = new LineDataSet(entriesGz, getString(R.string.gz)); dataSet1.setColor(Color.BLUE); @@ -397,32 +314,28 @@ protected void onPostExecute(Void aVoid) { mChartAcceleration.setData(data); mChartAcceleration.notifyDataSetChanged(); mChartAcceleration.setVisibleXRangeMaximum(10); - mChartAcceleration.moveViewToX(data.getEntryCount()); - mChartAcceleration.invalidate(); + mChartAcceleration.moveViewToX(timeElapsed); LineData data2 = new LineData(dataSets2); mChartGyroscope.setData(data2); mChartGyroscope.notifyDataSetChanged(); mChartGyroscope.setVisibleXRangeMaximum(10); - mChartGyroscope.moveViewToX(data2.getEntryCount()); - mChartGyroscope.invalidate(); - samplesEditBox.setText(String.valueOf(counter)); - if (counter == 0 && !runIndefinitely) { - play = false; - playPauseButton.setImageResource(R.drawable.circle_play_button); - } - synchronized (lock) { - lock.notify(); - } + mChartGyroscope.moveViewToX(timeElapsed); } } + @Override + protected AbstractSensorActivity.SensorDataFetch getSensorDataFetch() { + return sensorDataFetch; + } + + @Override + protected int getLayoutResId() { + return R.layout.sensor_mpu925x; + } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; + protected int getTitleResId() { + return R.string.mpu925x; } } diff --git a/app/src/main/java/io/pslab/sensors/SensorSHT21.java b/app/src/main/java/io/pslab/sensors/SensorSHT21.java index 9b4448c82..a5c4822b6 100644 --- a/app/src/main/java/io/pslab/sensors/SensorSHT21.java +++ b/app/src/main/java/io/pslab/sensors/SensorSHT21.java @@ -1,21 +1,12 @@ package io.pslab.sensors; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; -import android.view.MenuItem; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.RelativeLayout; -import android.widget.SeekBar; +import android.util.Log; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.Legend; @@ -27,107 +18,44 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.List; import io.pslab.DataFormatter; import io.pslab.R; -import io.pslab.communication.ScienceLab; import io.pslab.communication.peripherals.I2C; import io.pslab.communication.sensors.SHT21; -import io.pslab.others.ScienceLabCommon; -/** - * Created by Harsh on 6/6/18. - */ +public class SensorSHT21 extends AbstractSensorActivity { + private static final String TAG = SensorSHT21.class.getSimpleName(); -public class SensorSHT21 extends AppCompatActivity { - private static int counter; - private final Object lock = new Object(); - private ScienceLab scienceLab; - private SensorSHT21.SensorDataFetch sensorDataFetch; - private TextView tvSensorSHT21Temp; - private TextView tvSensorSHT21Humidity; + private static final String KEY_ENTRIES_TEMPERATURE = TAG + "_entries_temperature"; + private static final String KEY_ENTRIES_HUMIDITY = TAG + "_entries_humidity"; + private static final String KEY_VALUE_TEMP = TAG + "_value_temperature"; + private static final String KEY_VALUE_HUMIDITY = TAG + "_value_humidity"; + + private SensorDataFetch sensorDataFetch; private SHT21 sensorSHT21; - private LineChart mChartTemperature; - private LineChart mChartHumidity; - private long startTime; - private int flag; + private ArrayList entriesTemperature; private ArrayList entriesHumidity; - private RelativeLayout sensorDock; - private CheckBox indefiniteSamplesCheckBox; - private EditText samplesEditBox; - private SeekBar timeGapSeekbar; - private TextView timeGapLabel; - private ImageButton playPauseButton; - private boolean play; - private boolean runIndefinitely; - private int timeGap; + + private LineChart mChartTemperature; + private LineChart mChartHumidity; + private TextView tvSensorSHT21Temp; + private TextView tvSensorSHT21Humidity; @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sensor_sht21); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.sht21); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } - sensorDock = findViewById(R.id.sensor_control_dock_layout); - indefiniteSamplesCheckBox = findViewById(R.id.checkBox_samples_sensor); - samplesEditBox = findViewById(R.id.editBox_samples_sensors); - timeGapSeekbar = findViewById(R.id.seekBar_timegap_sensor); - timeGapLabel = findViewById(R.id.tv_timegap_label); - playPauseButton = findViewById(R.id.imageButton_play_pause_sensor); - setSensorDock(); - sensorDock.setVisibility(View.VISIBLE); - - scienceLab = ScienceLabCommon.scienceLab; - I2C i2c = scienceLab.i2c; + I2C i2c = getScienceLab().i2c; try { - sensorSHT21 = new SHT21(i2c, scienceLab); + sensorSHT21 = new SHT21(i2c, getScienceLab()); } catch (IOException | InterruptedException e) { - e.printStackTrace(); + Log.e(TAG, "Sensor initialization failed.", e); } - entriesTemperature = new ArrayList<>(); - entriesHumidity = new ArrayList<>(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - while (true) { - if (scienceLab.isConnected() && shouldPlay()) { - sensorDataFetch = new SensorSHT21.SensorDataFetch(); - sensorDataFetch.execute(); - - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - } - - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - try { - Thread.sleep(timeGap); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - }; - new Thread(runnable).start(); + sensorDataFetch = new SensorDataFetch(); tvSensorSHT21Temp = findViewById(R.id.tv_sensor_sht21_temp); tvSensorSHT21Humidity = findViewById(R.id.tv_sensor_sht21_humidity); @@ -202,95 +130,40 @@ public void run() { yHumidity2.setDrawGridLines(false); - } - - private boolean shouldPlay() { - if (play) { - if (indefiniteSamplesCheckBox.isChecked()) - return true; - else if (counter >= 0) { - counter--; - return true; - } else { - play = false; - return false; - } + if (savedInstanceState == null) { + entriesTemperature = new ArrayList<>(); + entriesHumidity = new ArrayList<>(); } else { - return false; - } - } + tvSensorSHT21Temp.setText(savedInstanceState.getString(KEY_VALUE_TEMP)); + tvSensorSHT21Humidity.setText(savedInstanceState.getString(KEY_VALUE_HUMIDITY)); - private void setSensorDock() { - play = false; - runIndefinitely = true; - timeGap = 100; - final int step = 1; - final int max = 1000; - final int min = 100; - - playPauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (play && scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else if (!scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else { - playPauseButton.setImageResource(R.drawable.circle_pause_button); - play = true; - if (!indefiniteSamplesCheckBox.isChecked()) { - counter = Integer.parseInt(samplesEditBox.getText().toString()); - } - } - } - }); - sensorDock.setVisibility(View.VISIBLE); - - indefiniteSamplesCheckBox.setChecked(true); - samplesEditBox.setEnabled(false); - indefiniteSamplesCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - runIndefinitely = true; - samplesEditBox.setEnabled(false); - } else { - runIndefinitely = false; - samplesEditBox.setEnabled(true); - } - } - }); - - timeGapSeekbar.setMax((max - min) / step); - timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - timeGap = min + (progress * step); - timeGapLabel.setText(timeGap + "ms"); - } + entriesTemperature = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_TEMPERATURE); + entriesHumidity = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_HUMIDITY); - @Override - public void onStartTrackingTouch(SeekBar seekBar) { + sensorDataFetch.updateUi(); + } + } - } + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); - @Override - public void onStopTrackingTouch(SeekBar seekBar) { + outState.putString(KEY_VALUE_TEMP, tvSensorSHT21Temp.getText().toString()); + outState.putString(KEY_VALUE_HUMIDITY, tvSensorSHT21Humidity.getText().toString()); - } - }); + outState.putParcelableArrayList(KEY_ENTRIES_TEMPERATURE, entriesTemperature); + outState.putParcelableArrayList(KEY_ENTRIES_HUMIDITY, entriesHumidity); } - private class SensorDataFetch extends AsyncTask { + private class SensorDataFetch extends AbstractSensorActivity.SensorDataFetch { - private ArrayList dataSHT21Temp = new ArrayList<>(); - private ArrayList dataSHT21Humidity = new ArrayList<>(); - private long timeElapsed; + private List dataSHT21Temp = new ArrayList<>(); + private List dataSHT21Humidity = new ArrayList<>(); + /* Initialization required if updateUi is executed before getSensorData */ + private float timeElapsed = getTimeElapsed(); @Override - protected Void doInBackground(Void... params) { + public void getSensorData() { try { if (sensorSHT21 != null) { sensorSHT21.selectParameter("temperature"); @@ -299,18 +172,19 @@ protected Void doInBackground(Void... params) { dataSHT21Humidity = sensorSHT21.getRaw(); } } catch (IOException | InterruptedException e) { - e.printStackTrace(); + Log.e(TAG, "Error getting sensor data.", e); } - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; - entriesTemperature.add(new Entry((float) timeElapsed, dataSHT21Temp.get(0).floatValue())); - entriesTemperature.add(new Entry((float) timeElapsed, dataSHT21Humidity.get(0).floatValue())); - return null; + timeElapsed = getTimeElapsed(); + entriesTemperature.add(new Entry(timeElapsed, dataSHT21Temp.get(0).floatValue())); + entriesTemperature.add(new Entry(timeElapsed, dataSHT21Humidity.get(0).floatValue())); } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - tvSensorSHT21Temp.setText(DataFormatter.formatDouble(dataSHT21Temp.get(0), DataFormatter.HIGH_PRECISION_FORMAT)); - tvSensorSHT21Humidity.setText(DataFormatter.formatDouble(dataSHT21Humidity.get(0), DataFormatter.HIGH_PRECISION_FORMAT)); + public void updateUi() { + + if (isSensorDataAcquired()) { + tvSensorSHT21Temp.setText(DataFormatter.formatDouble(dataSHT21Temp.get(0), DataFormatter.HIGH_PRECISION_FORMAT)); + tvSensorSHT21Humidity.setText(DataFormatter.formatDouble(dataSHT21Humidity.get(0), DataFormatter.HIGH_PRECISION_FORMAT)); + } LineDataSet dataSet1 = new LineDataSet(entriesTemperature, getString(R.string.temperature)); LineDataSet dataSet2 = new LineDataSet(entriesHumidity, getString(R.string.humidity)); @@ -322,31 +196,28 @@ protected void onPostExecute(Void aVoid) { mChartTemperature.setData(data); mChartTemperature.notifyDataSetChanged(); mChartTemperature.setVisibleXRangeMaximum(10); - mChartTemperature.moveViewToX(data.getEntryCount()); - mChartTemperature.invalidate(); + mChartTemperature.moveViewToX(timeElapsed); LineData data2 = new LineData(dataSet2); mChartHumidity.setData(data2); mChartHumidity.notifyDataSetChanged(); mChartHumidity.setVisibleXRangeMaximum(10); - mChartHumidity.moveViewToX(data2.getEntryCount()); - mChartHumidity.invalidate(); - samplesEditBox.setText(String.valueOf(counter)); - if (counter == 0 && !runIndefinitely) { - play = false; - playPauseButton.setImageResource(R.drawable.circle_play_button); - } - synchronized (lock) { - lock.notify(); - } + mChartHumidity.moveViewToX(timeElapsed); } } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; + protected AbstractSensorActivity.SensorDataFetch getSensorDataFetch() { + return sensorDataFetch; + } + + @Override + protected int getLayoutResId() { + return R.layout.sensor_sht21; + } + + @Override + protected int getTitleResId() { + return R.string.sht21; } } diff --git a/app/src/main/java/io/pslab/sensors/SensorTSL2561.java b/app/src/main/java/io/pslab/sensors/SensorTSL2561.java index 805d566cf..47918c6b2 100644 --- a/app/src/main/java/io/pslab/sensors/SensorTSL2561.java +++ b/app/src/main/java/io/pslab/sensors/SensorTSL2561.java @@ -1,22 +1,14 @@ package io.pslab.sensors; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; -import android.view.MenuItem; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; +import android.util.Log; import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.RelativeLayout; -import android.widget.SeekBar; import android.widget.Spinner; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.Legend; @@ -32,122 +24,61 @@ import java.util.List; import io.pslab.R; -import io.pslab.communication.ScienceLab; import io.pslab.communication.peripherals.I2C; import io.pslab.communication.sensors.TSL2561; -import io.pslab.others.ScienceLabCommon; -/** - * Created by Harsh on 6/6/18. - */ +public class SensorTSL2561 extends AbstractSensorActivity { + private static final String TAG = SensorTSL2561.class.getSimpleName(); + + private static final String KEY_ENTRIES_FULL = TAG + "_entries_full"; + private static final String KEY_ENTRIES_INFRARED = TAG + "_entries_infrared"; + private static final String KEY_ENTRIES_VISIBLE = TAG + "_entries_visible"; + private static final String KEY_VALUE_FULL = TAG + "_value_full"; + private static final String KEY_VALUE_INFRARED = TAG + "_value_infrared"; + private static final String KEY_VALUE_VISIBLE = TAG + "_value_visible"; + private static final String KEY_VALUE_TIMING = TAG + "_value_timing"; + private static final String KEY_POS_GAIN = TAG + "_pos_gain"; -public class SensorTSL2561 extends AppCompatActivity { - private static int counter; - private final Object lock = new Object(); - private ScienceLab scienceLab; private SensorTSL2561.SensorDataFetch sensorDataFetch; - private TextView tvSensorTSL2561FullSpectrum; - private TextView tvSensorTSL2561Infrared; - private TextView tvSensorTSL2561Visible; - private EditText etSensorTSL2561Timing; private TSL2561 sensorTSL2561; - private LineChart mChart; - private long startTime; - private int flag; + private ArrayList entriesFull; private ArrayList entriesInfrared; private ArrayList entriesVisible; - private RelativeLayout sensorDock; - private CheckBox indefiniteSamplesCheckBox; - private EditText samplesEditBox; - private SeekBar timeGapSeekbar; - private TextView timeGapLabel; - private ImageButton playPauseButton; - private boolean play; - private boolean runIndefinitely; - private int timeGap; + + private LineChart mChart; + private TextView tvSensorTSL2561FullSpectrum; + private TextView tvSensorTSL2561Infrared; + private TextView tvSensorTSL2561Visible; + private EditText etSensorTSL2561Timing; + private Spinner spinnerSensorTSL2561Gain; @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sensor_tsl2561); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.tsl2561); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } - sensorDock = findViewById(R.id.sensor_control_dock_layout); - indefiniteSamplesCheckBox = findViewById(R.id.checkBox_samples_sensor); - samplesEditBox = findViewById(R.id.editBox_samples_sensors); - timeGapSeekbar = findViewById(R.id.seekBar_timegap_sensor); - timeGapLabel = findViewById(R.id.tv_timegap_label); - playPauseButton = findViewById(R.id.imageButton_play_pause_sensor); - setSensorDock(); - sensorDock.setVisibility(View.VISIBLE); - - scienceLab = ScienceLabCommon.scienceLab; - I2C i2c = scienceLab.i2c; + I2C i2c = getScienceLab().i2c; try { - sensorTSL2561 = new TSL2561(i2c, scienceLab); + sensorTSL2561 = new TSL2561(i2c, getScienceLab()); } catch (IOException | InterruptedException e) { - e.printStackTrace(); + Log.e(TAG, "Sensor initialization failed.", e); } - entriesFull = new ArrayList<>(); - entriesInfrared = new ArrayList<>(); - entriesVisible = new ArrayList<>(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - while (true) { - if (scienceLab.isConnected() && shouldPlay()) { - try { - sensorDataFetch = new SensorTSL2561.SensorDataFetch(); - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - } - sensorDataFetch.execute(); - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - } - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - try { - Thread.sleep(timeGap); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - }; - new Thread(runnable).start(); + sensorDataFetch = new SensorDataFetch(); tvSensorTSL2561FullSpectrum = findViewById(R.id.tv_sensor_tsl2561_full); tvSensorTSL2561Infrared = findViewById(R.id.tv_sensor_tsl2561_infrared); tvSensorTSL2561Visible = findViewById(R.id.tv_sensor_tsl2561_visible); - Spinner spinnerSensorTSL2561Gain = findViewById(R.id.spinner_sensor_tsl2561_gain); + spinnerSensorTSL2561Gain = findViewById(R.id.spinner_sensor_tsl2561_gain); etSensorTSL2561Timing = findViewById(R.id.et_sensor_tsl2561_timing); mChart = findViewById(R.id.chart_tsl2561); try { - if (sensorTSL2561 != null & scienceLab.isConnected()) { + if (sensorTSL2561 != null & getScienceLab().isConnected()) { sensorTSL2561.setGain(spinnerSensorTSL2561Gain.getSelectedItem().toString()); } } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error setting gain.", e); } XAxis x = mChart.getXAxis(); @@ -184,117 +115,72 @@ public void run() { y2.setDrawGridLines(false); + if (savedInstanceState == null) { + entriesFull = new ArrayList<>(); + entriesInfrared = new ArrayList<>(); + entriesVisible = new ArrayList<>(); + } else { + spinnerSensorTSL2561Gain.setSelection(savedInstanceState.getInt(KEY_POS_GAIN)); - } + etSensorTSL2561Timing.setText(savedInstanceState.getString(KEY_VALUE_TIMING)); - private boolean shouldPlay() { - if (play) { - if (indefiniteSamplesCheckBox.isChecked()) - return true; - else if (counter >= 0) { - counter--; - return true; - } else { - play = false; - return false; - } - } else { - return false; + tvSensorTSL2561FullSpectrum.setText(savedInstanceState.getString(KEY_VALUE_FULL)); + tvSensorTSL2561Infrared.setText(savedInstanceState.getString(KEY_VALUE_INFRARED)); + tvSensorTSL2561Visible.setText(savedInstanceState.getString(KEY_VALUE_VISIBLE)); + + entriesFull = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_FULL); + entriesInfrared = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_INFRARED); + entriesVisible = savedInstanceState.getParcelableArrayList(KEY_ENTRIES_VISIBLE); + + sensorDataFetch.updateUi(); } } - private void setSensorDock() { - play = false; - runIndefinitely = true; - timeGap = 100; - final int step = 1; - final int max = 1000; - final int min = 100; - - playPauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (play && scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else if (!scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else { - playPauseButton.setImageResource(R.drawable.circle_pause_button); - play = true; - if (!indefiniteSamplesCheckBox.isChecked()) { - counter = Integer.parseInt(samplesEditBox.getText().toString()); - } - } - } - }); - sensorDock.setVisibility(View.VISIBLE); - - indefiniteSamplesCheckBox.setChecked(true); - samplesEditBox.setEnabled(false); - indefiniteSamplesCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - runIndefinitely = true; - samplesEditBox.setEnabled(false); - } else { - runIndefinitely = false; - samplesEditBox.setEnabled(true); - } - } - }); - - timeGapSeekbar.setMax((max - min) / step); - timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - timeGap = min + (progress * step); - timeGapLabel.setText(timeGap + "ms"); - } + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); - @Override - public void onStartTrackingTouch(SeekBar seekBar) { + outState.putInt(KEY_POS_GAIN, spinnerSensorTSL2561Gain.getSelectedItemPosition()); - } + outState.putString(KEY_VALUE_TIMING, etSensorTSL2561Timing.getText().toString()); - @Override - public void onStopTrackingTouch(SeekBar seekBar) { + outState.putString(KEY_VALUE_FULL, tvSensorTSL2561FullSpectrum.getText().toString()); + outState.putString(KEY_VALUE_INFRARED, tvSensorTSL2561Infrared.getText().toString()); + outState.putString(KEY_VALUE_VISIBLE, tvSensorTSL2561Visible.getText().toString()); - } - }); + outState.putParcelableArrayList(KEY_ENTRIES_FULL, entriesFull); + outState.putParcelableArrayList(KEY_ENTRIES_INFRARED, entriesInfrared); + outState.putParcelableArrayList(KEY_ENTRIES_VISIBLE, entriesVisible); } - private class SensorDataFetch extends AsyncTask { + private class SensorDataFetch extends AbstractSensorActivity.SensorDataFetch { private int[] dataTSL2561; - private long timeElapsed; - - private SensorDataFetch() throws IOException, InterruptedException { - } + /* Initialization required if updateUi is executed before getSensorData */ + private float timeElapsed = getTimeElapsed(); @Override - protected Void doInBackground(Void... params) { + public void getSensorData() { try { if (sensorTSL2561 != null) { dataTSL2561 = sensorTSL2561.getRaw(); } } catch (IOException e) { - e.printStackTrace(); + Log.e(TAG, "Error getting sensor data.", e); } - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; - entriesFull.add(new Entry((float) timeElapsed, dataTSL2561[0])); - entriesInfrared.add(new Entry((float) timeElapsed, dataTSL2561[1])); - entriesVisible.add(new Entry((float) timeElapsed, dataTSL2561[2])); - return null; + timeElapsed = getTimeElapsed(); + entriesFull.add(new Entry(timeElapsed, dataTSL2561[0])); + entriesInfrared.add(new Entry(timeElapsed, dataTSL2561[1])); + entriesVisible.add(new Entry(timeElapsed, dataTSL2561[2])); } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - tvSensorTSL2561FullSpectrum.setText(String.valueOf(dataTSL2561[0])); - tvSensorTSL2561Infrared.setText(String.valueOf(dataTSL2561[1])); - tvSensorTSL2561Visible.setText(String.valueOf(dataTSL2561[2])); + public void updateUi() { + + if (isSensorDataAcquired()) { + tvSensorTSL2561FullSpectrum.setText(String.valueOf(dataTSL2561[0])); + tvSensorTSL2561Infrared.setText(String.valueOf(dataTSL2561[1])); + tvSensorTSL2561Visible.setText(String.valueOf(dataTSL2561[2])); + } LineDataSet dataset1 = new LineDataSet(entriesFull, getString(R.string.full)); LineDataSet dataSet2 = new LineDataSet(entriesInfrared, getString(R.string.infrared)); @@ -317,25 +203,22 @@ protected void onPostExecute(Void aVoid) { mChart.setData(data); mChart.notifyDataSetChanged(); mChart.setVisibleXRangeMaximum(10); - mChart.moveViewToX(data.getEntryCount()); - mChart.invalidate(); - samplesEditBox.setText(String.valueOf(counter)); - if (counter == 0 && !runIndefinitely) { - play = false; - playPauseButton.setImageResource(R.drawable.circle_play_button); - } - synchronized (lock) { - lock.notify(); - } + mChart.moveViewToX(timeElapsed); } } + @Override + protected AbstractSensorActivity.SensorDataFetch getSensorDataFetch() { + return sensorDataFetch; + } + + @Override + protected int getLayoutResId() { + return R.layout.sensor_tsl2561; + } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; + protected int getTitleResId() { + return R.string.tsl2561; } } diff --git a/app/src/main/java/io/pslab/sensors/SensorVL53L0X.java b/app/src/main/java/io/pslab/sensors/SensorVL53L0X.java index c45b3a041..55349c475 100644 --- a/app/src/main/java/io/pslab/sensors/SensorVL53L0X.java +++ b/app/src/main/java/io/pslab/sensors/SensorVL53L0X.java @@ -1,22 +1,12 @@ package io.pslab.sensors; import android.graphics.Color; -import android.os.AsyncTask; import android.os.Bundle; -import android.view.MenuItem; -import android.view.View; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.RelativeLayout; -import android.widget.SeekBar; -import android.widget.Spinner; +import android.util.Log; import android.widget.TextView; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.Legend; @@ -30,94 +20,35 @@ import java.util.ArrayList; import io.pslab.R; -import io.pslab.communication.ScienceLab; import io.pslab.communication.peripherals.I2C; -import io.pslab.communication.sensors.ADS1115; import io.pslab.communication.sensors.VL53L0X; -import io.pslab.others.ScienceLabCommon; -public class SensorVL53L0X extends AppCompatActivity { - private static int counter; - private final Object lock = new Object(); - private ScienceLab scienceLab; - private SensorVL53L0X.SensorDataFetch sensorDataFetch; - private TextView tvSensorVL53L0X; - private LineChart mChart; - private long startTime; - private int flag; - private ArrayList entries; - private RelativeLayout sensorDock; - private CheckBox indefiniteSamplesCheckBox; - private EditText samplesEditBox; - private SeekBar timeGapSeekbar; - private TextView timeGapLabel; - private ImageButton playPauseButton; - private boolean play; - private boolean runIndefinitely; - private int timeGap; +public class SensorVL53L0X extends AbstractSensorActivity { + private static final String TAG = SensorVL53L0X.class.getSimpleName(); + private static final String KEY_ENTRIES = TAG + "_entries"; + private static final String KEY_VALUE = TAG + "_value"; + + private SensorDataFetch sensorDataFetch; private VL53L0X sensorVL53L0X; + private ArrayList entries; + + private LineChart mChart; + private TextView tvSensorVL53L0X; + @Override - protected void onCreate(Bundle savedInstanceState) { + protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.sensor_vl53l0x); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.vl53l0x); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } - sensorDock = findViewById(R.id.sensor_control_dock_layout); - indefiniteSamplesCheckBox = findViewById(R.id.checkBox_samples_sensor); - samplesEditBox = findViewById(R.id.editBox_samples_sensors); - timeGapSeekbar = findViewById(R.id.seekBar_timegap_sensor); - timeGapLabel = findViewById(R.id.tv_timegap_label); - playPauseButton = findViewById(R.id.imageButton_play_pause_sensor); - setSensorDock(); - sensorDock.setVisibility(View.VISIBLE); - - scienceLab = ScienceLabCommon.scienceLab; - I2C i2c = scienceLab.i2c; - entries = new ArrayList<>(); + I2C i2c = getScienceLab().i2c; try { - sensorVL53L0X = new VL53L0X(i2c, scienceLab); + sensorVL53L0X = new VL53L0X(i2c, getScienceLab()); } catch (Exception e) { - e.printStackTrace(); + Log.e(TAG, "Sensor initialization failed.", e); } - Runnable runnable = new Runnable() { - @Override - public void run() { - while (true) { - if (scienceLab.isConnected() && shouldPlay()) { - sensorDataFetch = new SensorVL53L0X.SensorDataFetch(); - sensorDataFetch.execute(); - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - } - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - try { - Thread.sleep(timeGap); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - }; - new Thread(runnable).start(); + sensorDataFetch = new SensorDataFetch(); tvSensorVL53L0X = findViewById(R.id.tv_sensor_vl53l0x); mChart = findViewById(R.id.chart_sensor_ads); @@ -154,111 +85,52 @@ public void run() { y.setLabelCount(10); y2.setDrawGridLines(false); - } - private boolean shouldPlay() { - if (play) { - if (indefiniteSamplesCheckBox.isChecked()) - return true; - else if (counter >= 0) { - counter--; - return true; - } else { - play = false; - return false; - } + if (savedInstanceState == null) { + entries = new ArrayList<>(); } else { - return false; + tvSensorVL53L0X.setText(savedInstanceState.getString(KEY_VALUE)); + + entries = savedInstanceState.getParcelableArrayList(KEY_ENTRIES); + + sensorDataFetch.updateUi(); } } - private void setSensorDock() { - play = false; - runIndefinitely = true; - timeGap = 100; - final int step = 1; - final int max = 1000; - final int min = 100; - - playPauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (play && scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else if (!scienceLab.isConnected()) { - playPauseButton.setImageResource(R.drawable.circle_play_button); - play = false; - } else { - playPauseButton.setImageResource(R.drawable.circle_pause_button); - play = true; - if (!indefiniteSamplesCheckBox.isChecked()) { - counter = Integer.parseInt(samplesEditBox.getText().toString()); - } - } - } - }); - sensorDock.setVisibility(View.VISIBLE); - - indefiniteSamplesCheckBox.setChecked(true); - samplesEditBox.setEnabled(false); - indefiniteSamplesCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - runIndefinitely = true; - samplesEditBox.setEnabled(false); - } else { - runIndefinitely = false; - samplesEditBox.setEnabled(true); - } - } - }); - - timeGapSeekbar.setMax((max - min) / step); - timeGapSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - timeGap = min + (progress * step); - timeGapLabel.setText(timeGap + "ms"); - } + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - // Do nothing - } + outState.putString(KEY_VALUE, tvSensorVL53L0X.getText().toString()); - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - // Do nothing - } - }); + outState.putParcelableArrayList(KEY_ENTRIES, entries); } - private class SensorDataFetch extends AsyncTask { + private class SensorDataFetch extends AbstractSensorActivity.SensorDataFetch { private int dataVL53L0X; - private long timeElapsed; + /* Initialization required if updateUi is executed before getSensorData */ + private float timeElapsed = getTimeElapsed(); @Override - protected Void doInBackground(Void... params) { + public void getSensorData() { try { if (sensorVL53L0X != null) { dataVL53L0X = sensorVL53L0X.getRaw(); } - } catch (Exception e) { - e.printStackTrace(); + } catch (IOException e) { + Log.e(TAG, "Error getting sensor data.", e); } - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; - entries.add(new Entry((float) timeElapsed, dataVL53L0X)); - - return null; + timeElapsed = getTimeElapsed(); + entries.add(new Entry(timeElapsed, (float) dataVL53L0X)); } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - tvSensorVL53L0X.setText(String.valueOf(dataVL53L0X)); + public void updateUi() { + + if (isSensorDataAcquired()) { + tvSensorVL53L0X.setText(String.valueOf(dataVL53L0X)); + } LineDataSet dataSet = new LineDataSet(entries, getString(R.string.bx)); dataSet.setDrawCircles(true); @@ -266,24 +138,22 @@ protected void onPostExecute(Void aVoid) { mChart.setData(data); mChart.notifyDataSetChanged(); mChart.setVisibleXRangeMaximum(10); - mChart.moveViewToX(data.getEntryCount()); - mChart.invalidate(); - samplesEditBox.setText(String.valueOf(counter)); - if (counter == 0 && !runIndefinitely) { - play = false; - playPauseButton.setImageResource(R.drawable.circle_play_button); - } - synchronized (lock) { - lock.notify(); - } + mChart.moveViewToX(timeElapsed); } } @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - } - return true; + protected AbstractSensorActivity.SensorDataFetch getSensorDataFetch() { + return sensorDataFetch; + } + + @Override + protected int getLayoutResId() { + return R.layout.sensor_vl53l0x; + } + + @Override + protected int getTitleResId() { + return R.string.vl53l0x; } } diff --git a/app/src/main/res/layout/sensor_ads1115.xml b/app/src/main/res/layout/sensor_ads1115.xml index 9f5b4ef35..29acc012c 100644 --- a/app/src/main/res/layout/sensor_ads1115.xml +++ b/app/src/main/res/layout/sensor_ads1115.xml @@ -326,74 +326,6 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/sensor_apds9960.xml b/app/src/main/res/layout/sensor_apds9960.xml index bee350dbc..11787e8ea 100644 --- a/app/src/main/res/layout/sensor_apds9960.xml +++ b/app/src/main/res/layout/sensor_apds9960.xml @@ -833,74 +833,6 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/sensor_bmp180.xml b/app/src/main/res/layout/sensor_bmp180.xml index ab92b00a1..9ef506011 100644 --- a/app/src/main/res/layout/sensor_bmp180.xml +++ b/app/src/main/res/layout/sensor_bmp180.xml @@ -517,74 +517,6 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/sensor_ccs811.xml b/app/src/main/res/layout/sensor_ccs811.xml index 137ef5040..9e6cacede 100644 --- a/app/src/main/res/layout/sensor_ccs811.xml +++ b/app/src/main/res/layout/sensor_ccs811.xml @@ -378,74 +378,6 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/sensor_control_dock.xml b/app/src/main/res/layout/sensor_control_dock.xml new file mode 100644 index 000000000..e26e44d8a --- /dev/null +++ b/app/src/main/res/layout/sensor_control_dock.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/sensor_hmc5883l.xml b/app/src/main/res/layout/sensor_hmc5883l.xml index 5edf8a877..d43f87c26 100644 --- a/app/src/main/res/layout/sensor_hmc5883l.xml +++ b/app/src/main/res/layout/sensor_hmc5883l.xml @@ -272,74 +272,6 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/sensor_mlx90614.xml b/app/src/main/res/layout/sensor_mlx90614.xml index 5ce08ee89..57fc4ce48 100644 --- a/app/src/main/res/layout/sensor_mlx90614.xml +++ b/app/src/main/res/layout/sensor_mlx90614.xml @@ -377,74 +377,6 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/sensor_mpu6050.xml b/app/src/main/res/layout/sensor_mpu6050.xml index f400a7332..8cf211288 100644 --- a/app/src/main/res/layout/sensor_mpu6050.xml +++ b/app/src/main/res/layout/sensor_mpu6050.xml @@ -411,74 +411,6 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/sensor_mpu925x.xml b/app/src/main/res/layout/sensor_mpu925x.xml index 3f9bff8fd..58dc501c7 100644 --- a/app/src/main/res/layout/sensor_mpu925x.xml +++ b/app/src/main/res/layout/sensor_mpu925x.xml @@ -73,7 +73,7 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/sensor_sht21.xml b/app/src/main/res/layout/sensor_sht21.xml index 18a91bc21..5c4086af0 100644 --- a/app/src/main/res/layout/sensor_sht21.xml +++ b/app/src/main/res/layout/sensor_sht21.xml @@ -378,74 +378,6 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/sensor_tsl2561.xml b/app/src/main/res/layout/sensor_tsl2561.xml index 53cb1f739..c6372fe60 100644 --- a/app/src/main/res/layout/sensor_tsl2561.xml +++ b/app/src/main/res/layout/sensor_tsl2561.xml @@ -106,8 +106,8 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/sensor_vl53l0x.xml b/app/src/main/res/layout/sensor_vl53l0x.xml index adf255e97..2f4674e64 100644 --- a/app/src/main/res/layout/sensor_vl53l0x.xml +++ b/app/src/main/res/layout/sensor_vl53l0x.xml @@ -227,74 +227,6 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index e071508da..3b86bf742 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -489,7 +489,7 @@ الجدول الزمني والزناد تحليل البيانات س ص مؤامرة - 100MS + 100 MS - تحديد قيمة @@ -972,4 +972,5 @@ الموقع غير محدد 0 مجهول + \\u0020MS \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index e3ab67726..61363df69 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -493,7 +493,7 @@ Podstawa czasu i wyzwalacz Analiza danych XY Plot - 100ms + 100 ms - + Wybierz wartość @@ -1036,5 +1036,6 @@ Lokalizacja nie jest określona 0 Nieznany + \\u0020ms diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 9e0998fd2..e7ea2395b 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -496,7 +496,7 @@ База времени и триггерjd Анализ данных XY Plot - 100ms + 100 ms - + Выберите значение @@ -1056,4 +1056,5 @@ 0 неизвестный Разработчики + \\u0020ms \ No newline at end of file diff --git a/app/src/main/res/values-si/string.xml b/app/src/main/res/values-si/string.xml index de6416d6e..73618b476 100644 --- a/app/src/main/res/values-si/string.xml +++ b/app/src/main/res/values-si/string.xml @@ -493,7 +493,7 @@ කාලරාමුව සහ ප්‍රේරකය දත්ත විශ්ලේෂණය XY Plot - 100ms + 100 ms - + අගයක් තෝරන්න @@ -1025,4 +1025,5 @@ නොදන්නා යෙදුම ශ්‍රේණිගත කරන්න සංවර්ධකයින් + \\u0020ms diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1c424926e..1de834d4f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -524,7 +524,7 @@ Timebase and Trigger Data Analysis XY Plot - 100ms + 100 ms - + Select a Value