{
139 | private static final int USB_TIMEOUT = 1000;
140 |
141 | // Assumes for now command <= 52 bytes long.
142 | protected void send_command(String command) {
143 | _mbtag = (byte) ((_mbtag % 255) + 1);
144 | _packet_buffer.clear();
145 | _packet_buffer.put(USBTMC_MSGID_DEV_DEP_MSG_OUT);
146 | _packet_buffer.put(_mbtag);
147 | _packet_buffer.put((byte) (_mbtag ^ 0xff));
148 | _packet_buffer.put((byte) 0x00);
149 |
150 | _packet_buffer.putInt(command.length());
151 | _packet_buffer.put((byte) 0x01); // EoM
152 | _packet_buffer.put((byte) 0x00);
153 | _packet_buffer.put((byte) 0x00);
154 | _packet_buffer.put((byte) 0x00);
155 |
156 | _packet_buffer.put(command.getBytes());
157 | int length_padded = (_packet_buffer.position() + 3) - ((_packet_buffer.position() - 1) % 4);
158 |
159 | if (_connection != null) {
160 | _connection.bulkTransfer(_endpoint_out, _packet_buffer.array(), length_padded, USB_TIMEOUT);
161 | }
162 | }
163 |
164 | protected void request_data(int size) {
165 | _mbtag = (byte) ((_mbtag % 255) + 1);
166 | _packet_buffer.clear();
167 | _packet_buffer.put(USBTMC_MSGID_DEV_DEP_MSG_IN);
168 | _packet_buffer.put(_mbtag);
169 | _packet_buffer.put((byte) (_mbtag ^ 0xff));
170 | _packet_buffer.put((byte) 0x00);
171 |
172 | _packet_buffer.putInt(size);
173 | _packet_buffer.put((byte) 0x01);
174 | _packet_buffer.put((byte) 0x00);
175 | _packet_buffer.put((byte) 0x00);
176 | _packet_buffer.put((byte) 0x00);
177 |
178 | if (_connection != null) {
179 | _connection.bulkTransfer(_endpoint_out, _packet_buffer.array(), 12, USB_TIMEOUT);
180 | }
181 | }
182 |
183 | protected boolean receive_buffer(ByteBuffer bytes) {
184 | request_data(_max_packet_size - 12);
185 |
186 | _packet_buffer.clear();
187 |
188 | if (_connection == null) {
189 | return false;
190 | }
191 |
192 | int ret_size = _connection.bulkTransfer(_endpoint_in, _packet_buffer.array(), _max_packet_size, USB_TIMEOUT);
193 |
194 | if (ret_size > 0) {
195 | _packet_buffer.position(ret_size);
196 | _packet_buffer.flip();
197 | byte msgid = _packet_buffer.get();
198 | byte btag = _packet_buffer.get();
199 | byte btaginv = _packet_buffer.get();
200 | byte unused = _packet_buffer.get();
201 |
202 | int xfer_size = _packet_buffer.getInt();
203 | byte xfer_attr = _packet_buffer.get();
204 | unused = _packet_buffer.get();
205 | unused = _packet_buffer.get();
206 | unused = _packet_buffer.get();
207 | boolean eom = (xfer_attr & 0x01) == 1;
208 |
209 | bytes.put(_packet_buffer);
210 | return !eom;
211 | } else {
212 | return false;
213 | }
214 | }
215 |
216 | @Override
217 | protected byte[] doInBackground(Void... params) {
218 | String command = _command_queue.peek();
219 | send_command(command);
220 |
221 | if (command.endsWith("?")) {
222 | _result_buffer.clear();
223 | while (receive_buffer(_result_buffer)) {}
224 |
225 | return Arrays.copyOf(_result_buffer.array(), _result_buffer.position());
226 | }
227 |
228 | return null;
229 | }
230 |
231 | @Override
232 | protected void onPostExecute(byte[] result) {
233 | String command = _command_queue.remove();
234 | // Log.d("USBTMC <<<", command);
235 |
236 | if (_command_queue.size() > 0) {
237 | new GetDataTask().execute();
238 | }
239 |
240 | if (_result_callback != null) {
241 | _result_callback.result(command, result);
242 | }
243 | }
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/app/src/main/java/com/geospark/scoperoid/ViewAspectRatioMeasurer.java:
--------------------------------------------------------------------------------
1 | package com.geospark.scoperoid;
2 |
3 | import android.view.View.MeasureSpec;
4 |
5 | /**
6 | * This class is a helper to measure views that require a specific aspect ratio.
7 | *
8 | * The measurement calculation is differing depending on whether the height and width
9 | * are fixed (match_parent or a dimension) or not (wrap_content)
10 | *
11 | *
12 | * | Width fixed | Width dynamic |
13 | * ---------------+-------------+---------------|
14 | * Height fixed | 1 | 2 |
15 | * ---------------+-------------+---------------|
16 | * Height dynamic | 3 | 4 |
17 | *
18 | * Everything is measured according to a specific aspect ratio.
19 | *
20 | *
21 | * - 1: Both width and height fixed: Fixed (Aspect ratio isn't respected)
22 | * - 2: Width dynamic, height fixed: Set width depending on height
23 | * - 3: Width fixed, height dynamic: Set height depending on width
24 | * - 4: Both width and height dynamic: Largest size possible
25 | *
26 | *
27 | * @author Jesper Borgstrup
28 | */
29 | public class ViewAspectRatioMeasurer {
30 |
31 | private double aspectRatio;
32 |
33 | /**
34 | * Create a ViewAspectRatioMeasurer instance.
35 | *
36 | * Note: Don't construct a new instance everytime your View.onMeasure() method
37 | * is called.
38 | * Instead, create one instance when your View is constructed, and
39 | * use this instance's measure() methods in the onMeasure() method.
40 | * @param aspectRatio
41 | */
42 | public ViewAspectRatioMeasurer(double aspectRatio) {
43 | this.aspectRatio = aspectRatio;
44 | }
45 |
46 | /**
47 | * Measure with the aspect ratio given at construction.
48 | *
49 | * After measuring, get the width and height with the {@link #getMeasuredWidth()}
50 | * and {@link #getMeasuredHeight()} methods, respectively.
51 | * @param widthMeasureSpec The width MeasureSpec passed in your View.onMeasure() method
52 | * @param heightMeasureSpec The height MeasureSpec passed in your View.onMeasure() method
53 | */
54 | public void measure(int widthMeasureSpec, int heightMeasureSpec) {
55 | measure(widthMeasureSpec, heightMeasureSpec, this.aspectRatio);
56 | }
57 |
58 | /**
59 | * Measure with a specific aspect ratio
60 | *
61 | * After measuring, get the width and height with the {@link #getMeasuredWidth()}
62 | * and {@link #getMeasuredHeight()} methods, respectively.
63 | * @param widthMeasureSpec The width MeasureSpec passed in your View.onMeasure() method
64 | * @param heightMeasureSpec The height MeasureSpec passed in your View.onMeasure() method
65 | * @param aspectRatio The aspect ratio to calculate measurements in respect to
66 | */
67 | public void measure(int widthMeasureSpec, int heightMeasureSpec, double aspectRatio) {
68 | int widthMode = MeasureSpec.getMode(widthMeasureSpec);
69 | int widthSize = widthMode == MeasureSpec.UNSPECIFIED ? Integer.MAX_VALUE : MeasureSpec.getSize(widthMeasureSpec);
70 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
71 | int heightSize = heightMode == MeasureSpec.UNSPECIFIED ? Integer.MAX_VALUE : MeasureSpec.getSize( heightMeasureSpec );
72 |
73 | if ( heightMode == MeasureSpec.EXACTLY && widthMode == MeasureSpec.EXACTLY ) {
74 | /*
75 | * Possibility 1: Both width and height fixed
76 | */
77 | measuredWidth = widthSize;
78 | measuredHeight = heightSize;
79 |
80 | } else if ( heightMode == MeasureSpec.EXACTLY ) {
81 | /*
82 | * Possibility 2: Width dynamic, height fixed
83 | */
84 | measuredWidth = (int) Math.min( widthSize, heightSize * aspectRatio );
85 | measuredHeight = (int) (measuredWidth / aspectRatio);
86 |
87 | } else if ( widthMode == MeasureSpec.EXACTLY ) {
88 | /*
89 | * Possibility 3: Width fixed, height dynamic
90 | */
91 | measuredHeight = (int) Math.min( heightSize, widthSize / aspectRatio );
92 | measuredWidth = (int) (measuredHeight * aspectRatio);
93 |
94 | } else {
95 | /*
96 | * Possibility 4: Both width and height dynamic
97 | */
98 | if ( widthSize > heightSize * aspectRatio ) {
99 | measuredHeight = heightSize;
100 | measuredWidth = (int)( measuredHeight * aspectRatio );
101 | } else {
102 | measuredWidth = widthSize;
103 | measuredHeight = (int) (measuredWidth / aspectRatio);
104 | }
105 |
106 | }
107 | }
108 |
109 | private Integer measuredWidth = null;
110 | /**
111 | * Get the width measured in the latest call to measure().
112 | */
113 | public int getMeasuredWidth() {
114 | if ( measuredWidth == null ) {
115 | throw new IllegalStateException( "You need to run measure() before trying to get measured dimensions" );
116 | }
117 | return measuredWidth;
118 | }
119 |
120 | private Integer measuredHeight = null;
121 | /**
122 | * Get the height measured in the latest call to measure().
123 | */
124 | public int getMeasuredHeight() {
125 | if ( measuredHeight == null ) {
126 | throw new IllegalStateException( "You need to run measure() before trying to get measured dimensions" );
127 | }
128 | return measuredHeight;
129 | }
130 |
131 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/geospark/scoperoid/WaveformGrid.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015 GeoSpark
2 | //
3 | // Released under the MIT License (MIT)
4 | // See the LICENSE file, or visit http://opensource.org/licenses/MIT
5 |
6 | package com.geospark.scoperoid;
7 |
8 | import android.content.Context;
9 | import android.opengl.GLES20;
10 |
11 | import java.nio.ByteBuffer;
12 | import java.nio.ByteOrder;
13 | import java.nio.FloatBuffer;
14 |
15 | public class WaveformGrid {
16 | private static final String vertexShaderCode =
17 | "uniform mat4 uMVPMatrix;" +
18 | "attribute vec2 vPosition;" +
19 | "attribute vec2 aTexcoord;" +
20 | "varying vec2 vTexcoord;" +
21 | "void main() {" +
22 | " gl_Position = uMVPMatrix * vec4(vPosition, 0.3, 1.0);" +
23 | " vTexcoord = aTexcoord;" +
24 | "}";
25 |
26 | private static final String fragmentShaderCode =
27 | "precision mediump float;" +
28 | "uniform float brightness;" +
29 | "uniform sampler2D texture;" +
30 | "varying vec2 vTexcoord;" +
31 | "void main() {" +
32 | " vec4 gridColour = texture2D(texture, vTexcoord);" +
33 | " gridColour.a *= brightness;" +
34 | " gl_FragColor = gridColour;" +
35 | "}";
36 | private final int COORDS_PER_VERTEX = 2;
37 | private final int program;
38 | private final int vertexCount = 4;
39 | private final int vertexStride = COORDS_PER_VERTEX * 4;
40 | private float[] brightness = {0.5f};
41 | private FloatBuffer vertexBuffer;
42 | private FloatBuffer coordBuffer;
43 | private int grid_tex;
44 |
45 | public WaveformGrid(Context context) {
46 | grid_tex = WaveformRenderer.loadTexture(context, R.drawable.grid);
47 | program = WaveformRenderer.loadShader(vertexShaderCode, fragmentShaderCode);
48 |
49 | ByteBuffer bb = ByteBuffer.allocateDirect(vertexCount * vertexStride);
50 | bb.order(ByteOrder.nativeOrder());
51 | vertexBuffer = bb.asFloatBuffer();
52 | vertexBuffer.clear();
53 | vertexBuffer.put(0.0f);
54 | vertexBuffer.put(255.0f);
55 | vertexBuffer.put(0.0f);
56 | vertexBuffer.put(0.0f);
57 | vertexBuffer.put(1200.0f);
58 | vertexBuffer.put(255.0f);
59 | vertexBuffer.put(1200.0f);
60 | vertexBuffer.put(0.0f);
61 | vertexBuffer.flip();
62 |
63 | ByteBuffer bbtex = ByteBuffer.allocateDirect(vertexCount * vertexStride);
64 | bbtex.order(ByteOrder.nativeOrder());
65 | coordBuffer = bbtex.asFloatBuffer();
66 | coordBuffer.clear();
67 | coordBuffer.put(0.0f);
68 | coordBuffer.put(1.0f);
69 | coordBuffer.put(0.0f);
70 | coordBuffer.put(0.0f);
71 | coordBuffer.put(1.0f);
72 | coordBuffer.put(1.0f);
73 | coordBuffer.put(1.0f);
74 | coordBuffer.put(0.0f);
75 | coordBuffer.flip();
76 | }
77 |
78 | public void setBrightness(float brightness) {
79 | this.brightness[0] = brightness;
80 | }
81 |
82 | public void draw(float[] matrix) {
83 | GLES20.glUseProgram(program);
84 |
85 | int MVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
86 | GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, matrix, 0);
87 |
88 | int positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
89 | GLES20.glEnableVertexAttribArray(positionHandle);
90 | GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
91 | GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
92 |
93 | int coordHandle = GLES20.glGetAttribLocation(program, "aTexcoord");
94 | GLES20.glEnableVertexAttribArray(coordHandle);
95 | GLES20.glVertexAttribPointer(coordHandle, COORDS_PER_VERTEX,
96 | GLES20.GL_FLOAT, false, vertexStride, coordBuffer);
97 |
98 | int brightnessHandle = GLES20.glGetUniformLocation(program, "brightness");
99 | GLES20.glUniform1fv(brightnessHandle, 1, brightness, 0);
100 |
101 | int textureHandle = GLES20.glGetUniformLocation(program, "texture");
102 | GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
103 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, grid_tex);
104 | GLES20.glUniform1i(textureHandle, 0);
105 |
106 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);
107 |
108 | GLES20.glDisableVertexAttribArray(positionHandle);
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/java/com/geospark/scoperoid/WaveformLine.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015 GeoSpark
2 | //
3 | // Released under the MIT License (MIT)
4 | // See the LICENSE file, or visit http://opensource.org/licenses/MIT
5 |
6 | package com.geospark.scoperoid;
7 |
8 | import android.opengl.GLES20;
9 |
10 | import java.nio.ByteBuffer;
11 | import java.nio.ByteOrder;
12 | import java.nio.FloatBuffer;
13 |
14 | public class WaveformLine {
15 | private static final String vertexShaderCode =
16 | "uniform mat4 uMVPMatrix;" +
17 | "attribute vec2 vPosition;" +
18 | "void main() {" +
19 | " gl_Position = uMVPMatrix * vec4(vPosition, 0.2, 1.0);" +
20 | "}";
21 |
22 | private static final String fragmentShaderCode =
23 | "precision mediump float;" +
24 | "uniform vec4 vColor;" +
25 | "void main() {" +
26 | " gl_FragColor = vColor;" +
27 | "}";
28 |
29 | private final int COORDS_PER_VERTEX = 2;
30 | private final int program;
31 | private final int vertexCount = 1200;
32 | private final int vertexStride = COORDS_PER_VERTEX * 4;
33 | private float[] colour;
34 |
35 | private FloatBuffer vertexBuffer;
36 |
37 | public WaveformLine(float r, float g, float b) {
38 | colour = new float[4];
39 | colour[0] = r;
40 | colour[1] = g;
41 | colour[2] = b;
42 | colour[3] = 1.0f;
43 | program = WaveformRenderer.loadShader(vertexShaderCode, fragmentShaderCode);
44 | ByteBuffer bb = ByteBuffer.allocateDirect(vertexCount * vertexStride);
45 | bb.order(ByteOrder.nativeOrder());
46 | vertexBuffer = bb.asFloatBuffer();
47 | }
48 |
49 | public void setData(byte[] data) {
50 | vertexBuffer.clear();
51 |
52 | for (int i = 0; i < Math.min(vertexCount, data.length); ++i) {
53 | vertexBuffer.put((float)i);
54 | float y = (float)(data[i] & 0xff);
55 | // Empirically derived numbers to make the waveform fit the grid.
56 | vertexBuffer.put((y * 1.285f) - 35.0f);
57 | }
58 |
59 | vertexBuffer.flip();
60 | }
61 |
62 | public void draw(float[] matrix) {
63 | GLES20.glUseProgram(program);
64 |
65 | int MVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
66 | GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, matrix, 0);
67 |
68 | int positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
69 | GLES20.glEnableVertexAttribArray(positionHandle);
70 | GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX,
71 | GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
72 |
73 | int colorHandle = GLES20.glGetUniformLocation(program, "vColor");
74 | GLES20.glUniform4fv(colorHandle, 1, colour, 0);
75 |
76 | GLES20.glDrawArrays(GLES20.GL_LINE_STRIP, 0, vertexCount);
77 |
78 | GLES20.glDisableVertexAttribArray(positionHandle);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/geospark/scoperoid/WaveformRenderer.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015 GeoSpark
2 | //
3 | // Released under the MIT License (MIT)
4 | // See the LICENSE file, or visit http://opensource.org/licenses/MIT
5 |
6 | package com.geospark.scoperoid;
7 |
8 | import android.content.Context;
9 | import android.graphics.Bitmap;
10 | import android.graphics.BitmapFactory;
11 | import android.graphics.Color;
12 | import android.opengl.GLES20;
13 | import android.opengl.GLSurfaceView;
14 | import android.opengl.GLUtils;
15 | import android.opengl.Matrix;
16 | import android.os.Bundle;
17 | import android.os.Handler;
18 | import android.os.Message;
19 |
20 | import javax.microedition.khronos.egl.EGLConfig;
21 | import javax.microedition.khronos.opengles.GL10;
22 |
23 | public class WaveformRenderer implements GLSurfaceView.Renderer {
24 | private final float[] mMVPMatrix = new float[16];
25 | private final float[] mProjectionMatrix = new float[16];
26 | private final float[] mViewMatrix = new float[16];
27 | private Context context;
28 | private byte[] waveform_data = null;
29 | private WaveformLine line;
30 | private WaveformGrid grid;
31 |
32 | public Handler handler;
33 |
34 | Handler.Callback callback = new Handler.Callback() {
35 | @Override
36 | public boolean handleMessage(Message msg) {
37 | Bundle b = msg.getData();
38 | waveform_data = b.getByteArray("waveform");
39 | return true;
40 | }
41 | };
42 |
43 | public WaveformRenderer(Context context) {
44 | handler = new Handler(callback);
45 | this.context = context;
46 | }
47 |
48 | public static int loadShader(String vertexShaderCode, String fragmentShaderCode) {
49 | int vs = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
50 | int fs = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
51 | int program = GLES20.glCreateProgram();
52 |
53 | GLES20.glShaderSource(vs, vertexShaderCode);
54 | GLES20.glShaderSource(fs, fragmentShaderCode);
55 | GLES20.glCompileShader(vs);
56 | GLES20.glCompileShader(fs);
57 | GLES20.glAttachShader(program, vs);
58 | GLES20.glAttachShader(program, fs);
59 | GLES20.glLinkProgram(program);
60 |
61 | return program;
62 | }
63 |
64 | public static int loadTexture(final Context context, final int resourceId) {
65 | final int[] textureHandle = new int[1];
66 |
67 | GLES20.glGenTextures(1, textureHandle, 0);
68 |
69 | if (textureHandle[0] != 0) {
70 | final BitmapFactory.Options options = new BitmapFactory.Options();
71 | options.inScaled = false;
72 | final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
73 |
74 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
75 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
76 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
77 | GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
78 | bitmap.recycle();
79 | } else {
80 | throw new RuntimeException("Error loading texture.");
81 | }
82 |
83 | return textureHandle[0];
84 | }
85 |
86 | @Override
87 | public void onSurfaceCreated(GL10 unused, EGLConfig config) {
88 | GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
89 | GLES20.glDisable(GLES20.GL_DEPTH_TEST);
90 | GLES20.glEnable(GLES20.GL_BLEND);
91 | GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
92 | int c = context.getResources().getColor(R.color.channel1High);
93 | float r = (float)Color.red(c) / 255.0f;
94 | float g = (float)Color.green(c) / 255.0f;
95 | float b = (float)Color.blue(c) / 255.0f;
96 | line = new WaveformLine(r, g, b);
97 | grid = new WaveformGrid(context);
98 | grid.setBrightness(0.75f);
99 | }
100 |
101 | @Override
102 | public void onSurfaceChanged(GL10 unused, int width, int height) {
103 | GLES20.glViewport(0, 0, width, height);
104 | Matrix.orthoM(mProjectionMatrix, 0, 0.0f, 1200.0f, 0.0f, 255.0f, 0.1f, 10.0f);
105 | }
106 |
107 | @Override
108 | public void onDrawFrame(GL10 unused) {
109 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
110 | Matrix.setLookAtM(mViewMatrix, 0, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
111 | Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
112 |
113 | grid.draw(mMVPMatrix);
114 |
115 | if (waveform_data != null) {
116 | line.setData(waveform_data);
117 | line.draw(mMVPMatrix);
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/app/src/main/java/com/geospark/scoperoid/WaveformView.java:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015 GeoSpark
2 | //
3 | // Released under the MIT License (MIT)
4 | // See the LICENSE file, or visit http://opensource.org/licenses/MIT
5 |
6 | package com.geospark.scoperoid;
7 |
8 | import android.content.Context;
9 | import android.content.res.TypedArray;
10 | import android.opengl.GLSurfaceView;
11 | import android.os.Bundle;
12 | import android.os.Message;
13 | import android.util.AttributeSet;
14 | import android.util.Log;
15 |
16 | import java.io.UnsupportedEncodingException;
17 | import java.util.Arrays;
18 |
19 |
20 | public class WaveformView extends GLSurfaceView {
21 | private int mAspectRatioWidth;
22 | private int mAspectRatioHeight;
23 | private final WaveformRenderer mRenderer;
24 | private static final double VIEW_ASPECT_RATIO = 1.5;
25 | private ViewAspectRatioMeasurer varm = new ViewAspectRatioMeasurer(VIEW_ASPECT_RATIO);
26 |
27 | public WaveformView(Context context, AttributeSet attrs) {
28 | super(context, attrs);
29 |
30 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WaveformView);
31 |
32 | mAspectRatioWidth = a.getInt(R.styleable.WaveformView_aspectRatioWidth, 1);
33 | mAspectRatioHeight = a.getInt(R.styleable.WaveformView_aspectRatioHeight, 1);
34 |
35 | a.recycle();
36 |
37 | setEGLContextClientVersion(2);
38 | mRenderer = new WaveformRenderer(context);
39 |
40 | setRenderer(mRenderer);
41 | }
42 |
43 | public void setWaveformData(byte[] data) {
44 | // Bit of an assumption, ideally we read in the first two bytes to determine the length
45 | // of the rest of the header, but meh.
46 | byte[] hdr = Arrays.copyOfRange(data, 2, 11);
47 | int data_len;
48 |
49 | try {
50 | String s = new String(hdr, "US-ASCII");
51 | data_len = Integer.parseInt(s);
52 | } catch (UnsupportedEncodingException e) {
53 | return;
54 | }
55 |
56 | Message msg = Message.obtain(mRenderer.handler);
57 | Bundle b = new Bundle();
58 | b.putByteArray("waveform", Arrays.copyOfRange(data, 11, Math.min(data.length, data_len + 12)));
59 | msg.setData(b);
60 | msg.sendToTarget();
61 | }
62 |
63 | @Override
64 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
65 | varm.measure(widthMeasureSpec, heightMeasureSpec);
66 | setMeasuredDimension(varm.getMeasuredWidth(), varm.getMeasuredHeight());
67 | // int originalWidth = MeasureSpec.getSize(widthMeasureSpec);
68 | // int originalHeight = MeasureSpec.getSize(heightMeasureSpec);
69 | // int calculatedHeight = originalWidth * mAspectRatioHeight / mAspectRatioWidth;
70 | //
71 | // int finalWidth, finalHeight;
72 | //
73 | // if (calculatedHeight > originalHeight) {
74 | // finalWidth = originalHeight * mAspectRatioWidth / mAspectRatioHeight;
75 | // finalHeight = originalHeight;
76 | // } else {
77 | // finalWidth = originalWidth;
78 | // finalHeight = calculatedHeight;
79 | // }
80 | //
81 | //// float ar = (float)finalWidth / (float)finalHeight;
82 | //// Log.d("GRID", String.valueOf(finalWidth) + " x " + String.valueOf(finalHeight) + " (" + String.valueOf(ar) + ")");
83 | //
84 | // super.onMeasure(
85 | // MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY),
86 | // MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY));
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeoSpark/scoperoid/65c804cc42e7905fa661c93210da7ad9016d0c2d/app/src/main/res/drawable/button.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeoSpark/scoperoid/65c804cc42e7905fa661c93210da7ad9016d0c2d/app/src/main/res/drawable/grid.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rigol_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeoSpark/scoperoid/65c804cc42e7905fa661c93210da7ad9016d0c2d/app/src/main/res/drawable/rigol_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
17 |
18 |
26 |
27 |
36 |
37 |
46 |
47 |
56 |
57 |
66 |
67 |
77 |
78 |
79 |
80 |
89 |
90 |
97 |
98 |
99 |
108 |
114 |
115 |
116 |
125 |
126 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeoSpark/scoperoid/65c804cc42e7905fa661c93210da7ad9016d0c2d/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeoSpark/scoperoid/65c804cc42e7905fa661c93210da7ad9016d0c2d/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeoSpark/scoperoid/65c804cc42e7905fa661c93210da7ad9016d0c2d/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GeoSpark/scoperoid/65c804cc42e7905fa661c93210da7ad9016d0c2d/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #f8fc00
4 | #00fcf8
5 | #f800f8
6 | #0080f8
7 |
8 | #383810
9 | #103838
10 | #381438
11 | #102838
12 |
13 | #202400
14 | #002420
15 | #200020
16 | #001020
17 |
18 | #f8fcf8
19 | #f88000
20 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Scoperoid
3 |
4 | Settings
5 | Rigol logo
6 | Ch 1
7 | Ch 2
8 | Ch 3
9 | Ch 4
10 | Run/Stop
11 | H %1$.2f%2$s
12 | D %1$.2f%2$s
13 | s
14 | ms
15 | μs
16 | ns
17 | ps
18 | %1$.2f%2$s
19 | V
20 | mV
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/device_filter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------