Skip to content

Commit 301fdf1

Browse files
committed
it works
Signed-off-by: Andrey Parfenov <a1994ndrey@gmail.com>
1 parent c92676c commit 301fdf1

16 files changed

+445
-182
lines changed

app/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ dependencies {
3131
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
3232
implementation 'androidx.navigation:navigation-fragment:2.3.0'
3333
implementation 'androidx.navigation:navigation-ui:2.3.0'
34+
implementation 'com.github.michael-rapp:android-material-preferences:5.3.2'
35+
implementation 'com.jjoe64:graphview:4.2.2'
3436
testImplementation 'junit:junit:4.12'
3537
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
3638
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
37-
implementation 'com.github.michael-rapp:android-material-preferences:5.3.2'
3839
}

app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
package="com.example.brainflowplot">
44

5-
# for devices which use network
65
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
76
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
8-
# to use read/write file from/to SD card
97
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
108
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
119

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,48 @@
11
package com.example.brainflowplot;
22

3-
import android.content.Context;
43
import android.content.Intent;
54
import android.content.SharedPreferences;
5+
import android.graphics.Color;
66
import android.os.Bundle;
7+
import android.os.Handler;
78
import android.util.Log;
8-
import android.view.View;
9-
import android.widget.Toast;
109

1110
import com.google.android.material.bottomnavigation.BottomNavigationView;
1211

1312
import androidx.appcompat.app.AppCompatActivity;
1413
import androidx.navigation.NavController;
1514
import androidx.navigation.Navigation;
16-
import androidx.navigation.ui.AppBarConfiguration;
1715
import androidx.navigation.ui.NavigationUI;
1816
import androidx.preference.PreferenceManager;
1917

18+
import brainflow.AggOperations;
2019
import brainflow.BoardShim;
2120
import brainflow.BrainFlowError;
2221
import brainflow.BrainFlowInputParams;
22+
import brainflow.DataFilter;
2323

2424
public class DataActivity extends AppCompatActivity {
2525

26-
public BoardShim boardShim = null;
27-
public int samplingRate = 0;
28-
public int[] channels = null;
26+
// to dont sync threads for dataplot, bandpower, psd, etc each thread will has its own data array share boardShim object
27+
public static BoardShim boardShim = null;
28+
public static int samplingRate = 0;
29+
public static int[] channels = null;
2930

30-
private boolean isTryingToConnect = false;
31+
public static final int[] colors = {Color.BLUE, Color.YELLOW, Color.RED, Color.MAGENTA, Color.GREEN, Color.CYAN, Color.GRAY, Color.BLACK};
3132

3233
@Override
3334
protected void onCreate(Bundle savedInstanceState) {
3435
super.onCreate(savedInstanceState);
3536
setContentView(R.layout.activity_data);
3637
BottomNavigationView navView = findViewById(R.id.nav_view);
37-
// Passing each menu ID as a set of Ids because each
38-
// menu should be considered as top level destinations.
3938

40-
// comment out these two methods for theme wo actionbar
41-
/*
42-
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
43-
44-
R.id.navigation_dataplot, R.id.navigation_psdplot, R.id.navigation_bandpowerplot)
45-
.build();
46-
*/
4739
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
48-
// NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
4940
NavigationUI.setupWithNavController(navView, navController);
41+
}
5042

43+
@Override
44+
protected void onStart() {
45+
super.onStart();
5146
// read settings
5247
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
5348
int boardId = Integer.valueOf(prefs.getString(getString(R.string.board_id_key), "-1"));
@@ -60,41 +55,45 @@ protected void onCreate(Bundle savedInstanceState) {
6055
}
6156
String dataType = prefs.getString(getString(R.string.data_type_key), "");
6257

63-
boolean connected = false;
6458
try {
6559
BrainFlowInputParams params = new BrainFlowInputParams();
6660
params.ip_address = ipAddr;
6761
params.ip_port = ipPort;
6862
boardShim = new BoardShim(boardId, params);
63+
// prepare_session is relatively long operation, doing it in UI thread lead to black window for a few seconds
6964
boardShim.prepare_session();
7065
boardShim.start_stream();
71-
connected = true;
66+
samplingRate = BoardShim.get_sampling_rate(boardId);
67+
if (dataType.equals("EEG")) {
68+
channels = BoardShim.get_eeg_channels(boardId);
69+
} else {
70+
if (dataType.equals("EMG")) {
71+
channels = BoardShim.get_emg_channels(boardId);
72+
} else {
73+
channels = BoardShim.get_ecg_channels(boardId);
74+
}
75+
}
76+
SettingsActivity.isPrevFailed = false;
7277
} catch (Exception e) {
73-
Context context = getApplicationContext();
74-
CharSequence text = "Error occurred, validate provided parameters and your board";
75-
int duration = Toast.LENGTH_LONG;
76-
Toast toast = Toast.makeText(context, text, duration);
77-
toast.show();
7878
Log.e(getString(R.string.log_tag), e.getMessage());
79-
connected = false;
79+
SettingsActivity.isPrevFailed = true;
8080
}
81-
if (!connected) {
82-
// if failed to connect back to settings page
81+
if (SettingsActivity.isPrevFailed) {
82+
// if failed to connect go back to settings page
8383
Intent myIntent = new Intent(this, SettingsActivity.class);
8484
startActivity(myIntent);
8585
}
8686
}
8787

8888
@Override
89-
protected void onDestroy() {
89+
protected void onStop() {
9090
try {
9191
if (boardShim != null) {
9292
boardShim.release_session();
9393
}
9494
} catch (BrainFlowError e) {
9595
Log.e(getString(R.string.log_tag), e.getMessage());
9696
}
97-
super.onDestroy();
97+
super.onStop();
9898
}
99-
10099
}

app/src/main/java/com/example/brainflowplot/SettingsActivity.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
package com.example.brainflowplot;
22

3+
import android.content.Context;
34
import android.content.Intent;
45
import android.os.Bundle;
56
import android.view.View;
7+
import android.widget.Toast;
68

79
import androidx.appcompat.app.ActionBar;
810
import androidx.appcompat.app.AppCompatActivity;
911
import androidx.preference.PreferenceFragmentCompat;
1012

1113
public class SettingsActivity extends AppCompatActivity {
1214

15+
public static boolean isPrevFailed = false;
16+
1317
@Override
1418
protected void onCreate(Bundle savedInstanceState) {
1519
super.onCreate(savedInstanceState);
@@ -23,6 +27,14 @@ protected void onCreate(Bundle savedInstanceState) {
2327
if (actionBar != null) {
2428
actionBar.setDisplayHomeAsUpEnabled(true);
2529
}
30+
// make toast in this actvity
31+
if (isPrevFailed) {
32+
Context context = getApplicationContext();
33+
CharSequence text = "Error occurred, validate provided parameters and your board";
34+
int duration = Toast.LENGTH_LONG;
35+
Toast toast = Toast.makeText(context, text, duration);
36+
toast.show();
37+
}
2638
}
2739

2840
public void prepareSession(View view) {
Lines changed: 113 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,135 @@
11
package com.example.brainflowplot.ui.bandpowerplot;
22

3+
import android.graphics.Color;
34
import android.os.Bundle;
5+
import android.os.Handler;
6+
import android.util.Log;
47
import android.view.LayoutInflater;
58
import android.view.View;
69
import android.view.ViewGroup;
7-
import android.widget.TextView;
810

911
import androidx.annotation.NonNull;
10-
import androidx.annotation.Nullable;
1112
import androidx.fragment.app.Fragment;
12-
import androidx.lifecycle.Observer;
13-
import androidx.lifecycle.ViewModelProviders;
1413

14+
import com.example.brainflowplot.DataActivity;
1515
import com.example.brainflowplot.R;
16+
import com.jjoe64.graphview.GraphView;
17+
import com.jjoe64.graphview.GridLabelRenderer;
18+
import com.jjoe64.graphview.ValueDependentColor;
19+
import com.jjoe64.graphview.series.BarGraphSeries;
20+
import com.jjoe64.graphview.series.DataPoint;
21+
22+
import org.apache.commons.lang3.tuple.ImmutablePair;
23+
import org.apache.commons.lang3.tuple.Pair;
24+
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
28+
import brainflow.BrainFlowError;
29+
import brainflow.DataFilter;
30+
import brainflow.WindowFunctions;
31+
1632

1733
public class BandPowerPlotFragment extends Fragment {
1834

19-
private BandPowerPlotViewModel bandPowerPlotViewModel;
35+
public int windowSize = 2;
36+
public int timeSleep = 100;
37+
private GraphView graph = null;
38+
private BarGraphSeries<DataPoint> series= null;
39+
40+
private Runnable worker = null;
41+
private final Handler handler = new Handler();
42+
43+
private List<Pair<Integer, Integer>> bands = new ArrayList<Pair<Integer, Integer>>();
44+
private final String[] names = {"Delta", "Theta", "Alpha", "Beta", "Gamma"};
2045

2146
public View onCreateView(@NonNull LayoutInflater inflater,
2247
ViewGroup container, Bundle savedInstanceState) {
23-
bandPowerPlotViewModel =
24-
ViewModelProviders.of(this).get(BandPowerPlotViewModel.class);
25-
View root = inflater.inflate(R.layout.fragment_bandpowerplot, container, false);
26-
final TextView textView = root.findViewById(R.id.text_notifications);
27-
bandPowerPlotViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
48+
View rootView = inflater.inflate(R.layout.fragment_bandpowerplot, container, false);
49+
50+
graph = (GraphView) rootView.findViewById(R.id.bandpowergraph);
51+
graph.setTitle("BandPower");
52+
graph.getViewport().setXAxisBoundsManual(true);
53+
graph.getViewport().setMinX(0);
54+
graph.getViewport().setMaxX(5);
55+
graph.getViewport().setYAxisBoundsManual(true);
56+
graph.getViewport().setMinY(0);
57+
graph.getViewport().setMaxY(1);
58+
graph.getGridLabelRenderer().setVerticalLabelsVisible(false);
59+
graph.getGridLabelRenderer().setHorizontalLabelsVisible(false);
60+
graph.getGridLabelRenderer().setGridStyle(GridLabelRenderer.GridStyle.NONE);
61+
series = new BarGraphSeries<DataPoint>();
62+
series.setValueDependentColor(new ValueDependentColor<DataPoint>() {
2863
@Override
29-
public void onChanged(@Nullable String s) {
30-
textView.setText(s);
64+
public int get(DataPoint data) {
65+
return Color.rgb((int) data.getX() * 255 / 6, (int) Math.abs(data.getY() * 255 / 4), 100);
3166
}
3267
});
33-
return root;
68+
series.setTitle("Delta Theta Alpha Beta Gamma");
69+
70+
graph.addSeries(series);
71+
72+
bands.add(new ImmutablePair<Integer, Integer>(1, 4));
73+
bands.add(new ImmutablePair<Integer, Integer>(4, 8));
74+
bands.add(new ImmutablePair<Integer, Integer>(8, 13));
75+
bands.add(new ImmutablePair<Integer, Integer>(13, 30));
76+
bands.add(new ImmutablePair<Integer, Integer>(30, 70));
77+
78+
return rootView;
79+
}
80+
81+
@Override
82+
public void onResume() {
83+
super.onResume();
84+
85+
worker = new Runnable() {
86+
@Override
87+
public void run() {
88+
try {
89+
int numDataPoints = DataFilter.get_nearest_power_of_two(DataActivity.samplingRate * windowSize);
90+
double[][] tmpArray = DataActivity.boardShim.get_current_board_data(numDataPoints);
91+
if (tmpArray[0].length != numDataPoints) {
92+
// dont prepend, just wait for more data
93+
return;
94+
}
95+
// average across all channels
96+
DataPoint[] values = new DataPoint[bands.size()];
97+
for (int i = 0; i < values.length; i++) {
98+
values[i] = new DataPoint(i, 0);
99+
}
100+
for (int i = 0; i < DataActivity.channels.length; i++) {
101+
double[] channel = tmpArray[DataActivity.channels[i]];
102+
Pair<double[], double[]> psd = DataFilter.get_psd (channel, 0, channel.length, DataActivity.samplingRate, WindowFunctions.HAMMING.get_code ());
103+
for (int j = 0; j < bands.size(); j++) {
104+
double bandPower = DataFilter.get_band_power(psd, bands.get(j).getLeft(), bands.get(j).getRight());
105+
values[j] = new DataPoint(values[j].getX(), values[j].getY() + bandPower);
106+
}
107+
}
108+
// normalize for colors
109+
double max = 0;
110+
for (int j = 0; j < bands.size(); j++) {
111+
if (values[j].getY() > max) {
112+
max = values[j].getY();
113+
}
114+
}
115+
for (int j = 0; j < bands.size(); j++) {
116+
values[j] = new DataPoint(values[j].getX(), values[j].getY() / max);
117+
}
118+
series.resetData(values);
119+
} catch (BrainFlowError e) {
120+
Log.e(getString(R.string.log_tag), e.getMessage());
121+
}
122+
123+
handler.postDelayed(this, timeSleep);
124+
}
125+
};
126+
handler.postDelayed(worker, timeSleep);
127+
}
128+
129+
@Override
130+
public void onPause() {
131+
handler.removeCallbacks(worker);
132+
graph.removeAllSeries();
133+
super.onPause();
34134
}
35135
}

app/src/main/java/com/example/brainflowplot/ui/bandpowerplot/BandPowerPlotViewModel.java

Lines changed: 0 additions & 19 deletions
This file was deleted.

0 commit comments

Comments
 (0)