From 3555c1cf1f986d05879fe8d20a67dc56c55ef557 Mon Sep 17 00:00:00 2001 From: Jon McLin Date: Sat, 14 Nov 2015 14:46:26 -0700 Subject: [PATCH 1/2] Add a startup delay and a pace control to FileFragment. Delay allows user to switch to Avare after starting playback. Pace control plays back recorded data at approximately 2x the rate at which it was recorded, vs. as fast as possible. --- .../com/apps4av/avarehelper/FileFragment.java | 9 ++ .../connections/BlueToothConnectionIn.java | 2 - .../connections/BufferProcessor.java | 92 ++++++++++++------- .../connections/FileConnectionIn.java | 20 +++- app/src/main/res/layout/layout_play.xml | 30 +++++- app/src/main/res/values/strings.xml | 2 + 6 files changed, 117 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/com/apps4av/avarehelper/FileFragment.java b/app/src/main/java/com/apps4av/avarehelper/FileFragment.java index e40ed5f..55057fa 100644 --- a/app/src/main/java/com/apps4av/avarehelper/FileFragment.java +++ b/app/src/main/java/com/apps4av/avarehelper/FileFragment.java @@ -21,6 +21,7 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; +import android.widget.CheckBox; import com.apps4av.avarehelper.connections.FileConnectionIn; import com.apps4av.avarehelper.storage.Preferences; @@ -37,6 +38,8 @@ public class FileFragment extends Fragment { private Context mContext; private Button mConnectButton; private SavedEditText mTextFile; + private CheckBox mFileDelayCb; + private CheckBox mFileThrottleCb; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -81,8 +84,14 @@ public void onClick(View v) { /* * List of BT devices is same */ + + mFile = FileConnectionIn.getInstance(); + mFile.mFileDelayCb = (CheckBox)view.findViewById(R.id.main_cb_file_delay); + mFile.mFileThrottleCb = (CheckBox)view.findViewById(R.id.main_cb_file_throttle); + + setStates(); return view; diff --git a/app/src/main/java/com/apps4av/avarehelper/connections/BlueToothConnectionIn.java b/app/src/main/java/com/apps4av/avarehelper/connections/BlueToothConnectionIn.java index a11164c..a5abe92 100644 --- a/app/src/main/java/com/apps4av/avarehelper/connections/BlueToothConnectionIn.java +++ b/app/src/main/java/com/apps4av/avarehelper/connections/BlueToothConnectionIn.java @@ -121,8 +121,6 @@ public void start(final Preferences pref) { @Override public void run() { - Logger.Logit("WiFi reading data"); - BufferProcessor bp = new BufferProcessor(); Logger.Logit("BT reading data"); diff --git a/app/src/main/java/com/apps4av/avarehelper/connections/BufferProcessor.java b/app/src/main/java/com/apps4av/avarehelper/connections/BufferProcessor.java index 67d8609..cc2a346 100644 --- a/app/src/main/java/com/apps4av/avarehelper/connections/BufferProcessor.java +++ b/app/src/main/java/com/apps4av/avarehelper/connections/BufferProcessor.java @@ -12,6 +12,8 @@ package com.apps4av.avarehelper.connections; +import android.widget.CheckBox; + import com.apps4av.avarehelper.gdl90.BasicReportMessage; import com.apps4av.avarehelper.gdl90.Constants; import com.apps4av.avarehelper.gdl90.FisBuffer; @@ -41,6 +43,7 @@ public class BufferProcessor { private int mGeoAltitude = Integer.MIN_VALUE; + private long mLastTime = Long.MIN_VALUE; // Cache for last msg time to allow pacing. Should be instance variable, but no constructor. com.apps4av.avarehelper.gdl90.DataBuffer dbuffer = new com.apps4av.avarehelper.gdl90.DataBuffer(16384); @@ -51,7 +54,23 @@ public class BufferProcessor { com.apps4av.avarehelper.nmea.Decode ndecode = new com.apps4av.avarehelper.nmea.Decode(); Ownship nmeaOwnship = new Ownship(); + CheckBox paceOutput; + + private void pace(long mTime) { // method to pace messages when used with fileplayback + + int deltaT; + // Compute time since last message. If negative, assume 0. + // If set a maximum time, since this will delay updates. + deltaT = (int) java.lang.Math.min((int) java.lang.Math.max(0, (mTime - mLastTime)/2 ), 2000); + mLastTime = java.lang.Math.max(mTime, mLastTime); // Update if later. + // Wait deltaT milliseconds. + try { + Thread.sleep(deltaT); + } catch (InterruptedException e) { + return; // Not sure this is correct. REVIEW + } + } /** * * @param buffer @@ -69,14 +88,16 @@ public void put(byte [] buffer, int red) { public LinkedList decode(Preferences pref) { LinkedList objs = new LinkedList(); - + + long mTime = 0; + byte[] buf; - + while(null != (buf = nbuffer.get())) { com.apps4av.avarehelper.nmea.Message m = ndecode.decode(buf); if(m instanceof RTMMessage) { - + /* * Make a GPS locaiton message from ADSB ownship message. */ @@ -91,11 +112,13 @@ public LinkedList decode(Preferences pref) { object.put("altitude", (double)((double)tm.mAltitude)); object.put("callsign", (String)""); object.put("address", (int)tm.mIcaoAddress); - object.put("time", (long)tm.getTime()); + mTime=(long) tm.getTime(); + object.put("time", mTime); + } catch (JSONException e1) { continue; - } - + } + objs.add(object.toString()); } @@ -114,7 +137,8 @@ else if(nmeaOwnship.addMessage(m)) { object.put("speed", (double)(om.mHorizontalVelocity)); object.put("bearing", (double)om.mDirection); object.put("altitude", (double)((double)om.mAltitude)); - object.put("time", (long)om.getTime()); + mTime=(long) om.getTime(); + object.put("time", mTime); } catch (JSONException e1) { continue; } @@ -149,7 +173,8 @@ else if(nmeaOwnship.addMessage(m)) { object.put("altitude", (double)((double)tm.mAltitude)); object.put("callsign", (String)tm.mCallSign); object.put("address", (int)tm.mIcaoAddress); - object.put("time", (long)tm.getTime()); + mTime=(long) tm.getTime(); + object.put("time", mTime); } catch (JSONException e1) { continue; } @@ -159,7 +184,7 @@ else if(nmeaOwnship.addMessage(m)) { } else if(m instanceof BasicReportMessage) { - + /* * Make a GPS locaiton message from ADSB ownship message. */ @@ -174,16 +199,17 @@ else if(m instanceof BasicReportMessage) { object.put("altitude", (double)((double)tm.mAltitude)); object.put("callsign", (String)tm.mCallSign); object.put("address", (int)tm.mIcaoAddress); - object.put("time", (long)tm.getTime()); + mTime=(long) tm.getTime(); + object.put("time", mTime); } catch (JSONException e1) { continue; } - + objs.add(object.toString()); } else if(m instanceof LongReportMessage) { - + /* * Make a GPS locaiton message from ADSB ownship message. */ @@ -198,11 +224,12 @@ else if(m instanceof LongReportMessage) { object.put("altitude", (double)((double)tm.mAltitude)); object.put("callsign", (String)tm.mCallSign); object.put("address", (int)tm.mIcaoAddress); - object.put("time", (long)tm.getTime()); + mTime=(long) tm.getTime(); + object.put("time", mTime); } catch (JSONException e1) { continue; } - + objs.add(object.toString()); } @@ -223,10 +250,10 @@ else if(m instanceof UplinkMessage) { if(p instanceof Id6364Product) { Id6364Product pn = (Id6364Product)p; JSONObject object = new JSONObject(); - + JSONArray arrayEmpty = new JSONArray(); JSONArray arrayData = new JSONArray(); - + int[] data = pn.getData(); if(null != data) { for(int i = 0; i < data.length; i++) { @@ -239,10 +266,11 @@ else if(m instanceof UplinkMessage) { arrayEmpty.put(e); } } - + try { object.put("type", "nexrad"); - object.put("time", (long)pn.getTime().getTimeInMillis()); + mTime= (long) pn.getTime().getTimeInMillis(); + object.put("time", mTime); object.put("conus", pn.isConus()); object.put("blocknumber", (long)pn.getBlockNumber()); object.put("x", Constants.COLS_PER_BIN); @@ -252,7 +280,7 @@ else if(m instanceof UplinkMessage) { } catch (JSONException e1) { continue; } - + objs.add(object.toString()); } /* @@ -261,33 +289,33 @@ else if(m instanceof UplinkMessage) { else if(p instanceof Id413Product) { Id413Product pn = (Id413Product)p; JSONObject object = new JSONObject(); - + String data = pn.getData(); String type = pn.getHeader(); long time = (long)pn.getTime().getTimeInMillis(); - + /* * Clear garbage spaces etc. Convert to Avare format */ try { if(type.equals("WINDS")) { - + String tokens[] = data.split("\n"); if(tokens.length < 2) { /* * Must have line like - * MSY 230000Z FT 3000 6000 F9000 C12000 G18000 C24000 C30000 D34000 39000 Y + * MSY 230000Z FT 3000 6000 F9000 C12000 G18000 C24000 C30000 D34000 39000 Y * and second line like * 1410 2508+10 2521+07 2620+01 3037-12 3041-26 304843 295251 29765 */ continue; } - + tokens[0] = tokens[0].replaceAll("\\s+", " "); tokens[1] = tokens[1].replaceAll("\\s+", " "); String winds[] = tokens[1].split(" "); String alts[] = tokens[0].split(" "); - + /* * Start from 3rd entry - alts */ @@ -387,22 +415,23 @@ else if(p instanceof Id413Product) { catch (Exception e) { continue; } - + try { object.put("type", pn.getHeader()); + mTime=time; object.put("time", time); object.put("location", pn.getLocation()); object.put("data", data); } catch (JSONException e1) { continue; } - + objs.add(object.toString()); } } } else if(m instanceof OwnshipMessage) { - + /* * Make a GPS locaiton message from ADSB ownship message. */ @@ -414,7 +443,8 @@ else if(m instanceof OwnshipMessage) { object.put("latitude", (double)om.mLat); object.put("speed", (double)(om.mHorizontalVelocity)); object.put("bearing", (double)om.mDirection); - object.put("time", (long)om.getTime()); + mTime=(long) om.getTime(); + object.put("time", mTime); int altitude = -1000; if(pref.getGeoAltitude()) { altitude = mGeoAltitude; @@ -429,11 +459,11 @@ else if(m instanceof OwnshipMessage) { } catch (JSONException e1) { continue; } - + objs.add(object.toString()); } } - + if (paceOutput != null && paceOutput.isChecked()) pace(mTime); return objs; } } diff --git a/app/src/main/java/com/apps4av/avarehelper/connections/FileConnectionIn.java b/app/src/main/java/com/apps4av/avarehelper/connections/FileConnectionIn.java index 6dcd279..5a8045b 100644 --- a/app/src/main/java/com/apps4av/avarehelper/connections/FileConnectionIn.java +++ b/app/src/main/java/com/apps4av/avarehelper/connections/FileConnectionIn.java @@ -12,6 +12,8 @@ package com.apps4av.avarehelper.connections; +import android.widget.CheckBox; + import com.apps4av.avarehelper.storage.Preferences; import com.apps4av.avarehelper.utils.Logger; import com.ds.avare.IHelper; @@ -38,6 +40,9 @@ public class FileConnectionIn { private Thread mThread; private String mFileName = null; + public CheckBox mFileDelayCb; + public CheckBox mFileThrottleCb; + /** * @@ -86,7 +91,17 @@ public void start(final Preferences pref) { } mRunning = true; - + // When reading from file, wait for 5 seconds to allow user to switch to Avare. + if(mFileDelayCb.isChecked()) { + Logger.Logit("Delaying 5 seconds"); + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + return; + } + } + + /* * Thread that reads File */ @@ -98,7 +113,8 @@ public void run() { BufferProcessor bp = new BufferProcessor(); - + bp.paceOutput= mFileThrottleCb; + byte[] buffer = new byte[8192]; /* diff --git a/app/src/main/res/layout/layout_play.xml b/app/src/main/res/layout/layout_play.xml index 896adcf..92378f1 100644 --- a/app/src/main/res/layout/layout_play.xml +++ b/app/src/main/res/layout/layout_play.xml @@ -37,13 +37,37 @@ Redistribution and use in source and binary forms, with or without modification, android:layout_below="@+id/main_image_file" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/File"/> + android:text="@string/File" + /> + + + + +