diff --git a/.gitignore b/.gitignore
index 79256061..2c6ddf0f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,7 +7,6 @@
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
-/.idea
.DS_Store
/build
/captures
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 00000000..9acaff1d
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 00000000..79ee123c
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 00000000..7ac24c77
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..29bb4c57
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 00000000..7f68460d
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index c76a9378..bd3db2b8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -22,8 +22,8 @@ android {
applicationId "crazydude.com.telemetry"
minSdkVersion 16
targetSdkVersion 28
- versionCode 10
- versionName "1.1"
+ versionCode 11
+ versionName "1.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
diff --git a/app/src/main/java/crazydude/com/telemetry/manager/PreferenceManager.kt b/app/src/main/java/crazydude/com/telemetry/manager/PreferenceManager.kt
index 324bcf97..561441cb 100644
--- a/app/src/main/java/crazydude/com/telemetry/manager/PreferenceManager.kt
+++ b/app/src/main/java/crazydude/com/telemetry/manager/PreferenceManager.kt
@@ -41,4 +41,16 @@ class PreferenceManager(context: Context) {
fun setYoutubeShown() {
sharedPreferences.edit().putBoolean("youtube_shown", true).apply()
}
+
+ fun getBatteryUnits(): String {
+ return sharedPreferences.getString("battery_units", "mAh") ?: "mAh"
+ }
+
+ fun usePitotTube(): Boolean {
+ return sharedPreferences.getBoolean("use_pitot_tube", false)
+ }
+
+ fun showArtificialHorizonView(): Boolean {
+ return sharedPreferences.getBoolean("show_artificial_horizon", true)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/crazydude/com/telemetry/protocol/BluetoothDataPoller.kt b/app/src/main/java/crazydude/com/telemetry/protocol/BluetoothDataPoller.kt
index 1b12a51c..349617c1 100644
--- a/app/src/main/java/crazydude/com/telemetry/protocol/BluetoothDataPoller.kt
+++ b/app/src/main/java/crazydude/com/telemetry/protocol/BluetoothDataPoller.kt
@@ -30,10 +30,13 @@ class BluetoothDataPoller(
})
}
protocol = FrSkySportProtocol(dataDecoder)
+ val buffer = ByteArray(1024)
while (!thread.isInterrupted && bluetoothSocket.isConnected) {
- val data = bluetoothSocket.inputStream.read()
- outputStream?.write(data)
- protocol.process(data)
+ val size = bluetoothSocket.inputStream.read(buffer)
+ outputStream?.write(buffer, 0, size)
+ for (i in 0 until size) {
+ protocol.process(buffer[i].toInt())
+ }
}
} catch (e: IOException) {
try {
diff --git a/app/src/main/java/crazydude/com/telemetry/protocol/DataDecoder.kt b/app/src/main/java/crazydude/com/telemetry/protocol/DataDecoder.kt
index 82fea601..c38e85a0 100644
--- a/app/src/main/java/crazydude/com/telemetry/protocol/DataDecoder.kt
+++ b/app/src/main/java/crazydude/com/telemetry/protocol/DataDecoder.kt
@@ -150,6 +150,9 @@ class DataDecoder(private val listener: Listener) : FrSkySportProtocol.Companion
listener.onPitchData(value)
// Log.d(TAG, "Decoded pitch $value")
}
+ FrSkySportProtocol.ASPEED -> {
+ listener.onAirSpeed(data.data * 1.852f)
+ }
else -> {}
}
}
@@ -180,5 +183,6 @@ class DataDecoder(private val listener: Listener) : FrSkySportProtocol.Companion
firstFlightMode: FlyMode,
secondFlightMode: FlyMode?
)
+ fun onAirSpeed(speed: Float)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/crazydude/com/telemetry/protocol/FrskySportProtocol.kt b/app/src/main/java/crazydude/com/telemetry/protocol/FrskySportProtocol.kt
index 22e1f3ae..bcbe321f 100644
--- a/app/src/main/java/crazydude/com/telemetry/protocol/FrskySportProtocol.kt
+++ b/app/src/main/java/crazydude/com/telemetry/protocol/FrskySportProtocol.kt
@@ -43,6 +43,7 @@ class FrSkySportProtocol(var dataListener: DataListener) {
const val GPS_STATE_SENSOR = 0x0410
const val PITCH_SENSOR = 0x0430
const val ROLL_SENSOR = 0x0440
+ const val AIRSPEED_SENSOR = 0x0A00
const val FUEL = 0
const val GPS = 1
@@ -60,6 +61,7 @@ class FrSkySportProtocol(var dataListener: DataListener) {
const val ROLL = 13
const val PITCH = 14
const val GALT = 15
+ const val ASPEED = 16
interface DataListener {
fun onNewData(data: TelemetryData)
@@ -68,7 +70,7 @@ class FrSkySportProtocol(var dataListener: DataListener) {
@Retention(AnnotationRetention.SOURCE)
@IntDef(
FUEL, GPS, VBAT, CELL_VOLTAGE, CURRENT, HEADING, RSSI, FLYMODE, GPS_STATE, VSPEED, ALTITUDE, GSPEED,
- DISTANCE, ROLL, PITCH, GALT
+ DISTANCE, ROLL, PITCH, GALT, ASPEED
)
annotation class TelemetryType
@@ -258,6 +260,11 @@ class FrSkySportProtocol(var dataListener: DataListener) {
)
)
}
+ AIRSPEED_SENSOR -> {
+ dataListener.onNewData(
+ TelemetryData(ASPEED, rawData)
+ )
+ }
else -> {
//Log.d(TAG, "Unknown packet" + buffer.contentToString())
}
diff --git a/app/src/main/java/crazydude/com/telemetry/protocol/LogPlayer.kt b/app/src/main/java/crazydude/com/telemetry/protocol/LogPlayer.kt
index ee163974..dc0fb5e4 100644
--- a/app/src/main/java/crazydude/com/telemetry/protocol/LogPlayer.kt
+++ b/app/src/main/java/crazydude/com/telemetry/protocol/LogPlayer.kt
@@ -161,6 +161,10 @@ class LogPlayer(val originalListener: DataDecoder.Listener) : DataDecoder.Listen
originalListener.onRollData(rollAngle)
}
+ override fun onAirSpeed(speed: Float) {
+ originalListener.onAirSpeed(speed)
+ }
+
override fun onPitchData(pitchAngle: Float) {
originalListener.onPitchData(pitchAngle)
}
diff --git a/app/src/main/java/crazydude/com/telemetry/service/DataService.kt b/app/src/main/java/crazydude/com/telemetry/service/DataService.kt
index c409bcf9..0a7e5616 100644
--- a/app/src/main/java/crazydude/com/telemetry/service/DataService.kt
+++ b/app/src/main/java/crazydude/com/telemetry/service/DataService.kt
@@ -194,6 +194,12 @@ class DataService : Service(), DataDecoder.Listener {
})
}
+ override fun onAirSpeed(speed: Float) {
+ runOnMainThread(Runnable {
+ dataListener?.onAirSpeed(speed)
+ })
+ }
+
override fun onRSSIData(rssi: Int) {
runOnMainThread(Runnable {
dataListener?.onRSSIData(rssi)
diff --git a/app/src/main/java/crazydude/com/telemetry/ui/HorizonView.kt b/app/src/main/java/crazydude/com/telemetry/ui/HorizonView.kt
new file mode 100644
index 00000000..8ddc2ea0
--- /dev/null
+++ b/app/src/main/java/crazydude/com/telemetry/ui/HorizonView.kt
@@ -0,0 +1,94 @@
+package crazydude.com.telemetry.ui
+
+import android.content.Context
+import android.graphics.*
+import android.util.AttributeSet
+import android.view.View
+
+class HorizonView @JvmOverloads constructor(
+ context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
+) : View(context, attrs, defStyleAttr) {
+
+ private val paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
+ private var roll: Float = 0f
+ private var pitch: Float = 0f
+ private var size: Float = 0f
+ private var center: Float = 0f
+
+ private val leftLinePath = Path()
+ private val rightLinePath = Path()
+ private val circlePath = Path()
+
+ private val planeLinePaint = Paint(Paint.ANTI_ALIAS_FLAG)
+ .apply {
+ strokeWidth = 5f
+ style = Paint.Style.STROKE
+ }
+
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+ super.onSizeChanged(w, h, oldw, oldh)
+
+ size = w.toFloat()
+ center = size / 2
+
+ leftLinePath.apply {
+ moveTo(center - 100f, center)
+ lineTo(center - 20f, center)
+ lineTo(center - 20f, center + 10f)
+ }
+ rightLinePath.apply {
+ moveTo(center + 100f, center)
+ lineTo(center + 20f, center)
+ lineTo(center + 20f, center + 10f)
+ }
+ circlePath.apply {
+ addCircle(center, center, center, Path.Direction.CW)
+ }
+ }
+
+ override fun onDraw(canvas: Canvas?) {
+ super.onDraw(canvas)
+
+ canvas?.let {
+ it.save()
+ it.clipPath(circlePath, Region.Op.INTERSECT)
+ it.rotate(-roll, center, center)
+ paint.color = Color.parseColor("#5BCBD3")
+ it.drawRect(0f, 0f, size, center - pitch * 5, paint)
+ paint.color = Color.parseColor("#D38700")
+ it.drawRect(0f, center - pitch * 5, size, size, paint)
+ paint.strokeWidth = 4f
+ paint.color = Color.BLACK
+ for (i in 1..18) {
+ val lineLength = if (i.rem(2) == 0) 50 else 25
+ it.drawLine(
+ center - lineLength,
+ (center - pitch * 5) + i * 25,
+ center + lineLength,
+ (center - pitch * 5) + i * 25,
+ paint
+ )
+ it.drawLine(
+ center - lineLength,
+ (center - pitch * 5) - i * 25,
+ center + lineLength,
+ (center - pitch * 5) - i * 25,
+ paint
+ )
+ }
+ it.restore()
+ it.drawPath(leftLinePath, planeLinePaint)
+ it.drawPath(rightLinePath, planeLinePaint)
+ }
+ }
+
+ fun setRoll(roll: Float) {
+ this.roll = roll
+ invalidate()
+ }
+
+ fun setPitch(pitch: Float) {
+ this.pitch = pitch
+ invalidate()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/crazydude/com/telemetry/ui/MapsActivity.kt b/app/src/main/java/crazydude/com/telemetry/ui/MapsActivity.kt
index 6f969a7b..467ccfc7 100644
--- a/app/src/main/java/crazydude/com/telemetry/ui/MapsActivity.kt
+++ b/app/src/main/java/crazydude/com/telemetry/ui/MapsActivity.kt
@@ -66,6 +66,7 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, DataDecoder.Listen
private lateinit var mapTypeButton: FloatingActionButton
private lateinit var settingsButton: ImageView
private lateinit var topLayout: RelativeLayout
+ private lateinit var horizonView: HorizonView
private lateinit var preferenceManager: PreferenceManager
private var mapType = GoogleMap.MAP_TYPE_NORMAL
@@ -122,6 +123,7 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, DataDecoder.Listen
settingsButton = findViewById(R.id.settings_button)
replayButton = findViewById(R.id.replay_button)
seekBar = findViewById(R.id.seekbar)
+ horizonView = findViewById(R.id.horizon_view)
settingsButton.setOnClickListener {
startActivity(Intent(this, SettingsActivity::class.java))
@@ -329,6 +331,11 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, DataDecoder.Listen
}
marker?.setIcon(bitmapDescriptorFromVector(this, R.drawable.ic_plane, preferenceManager.getPlaneColor()))
}
+ if (preferenceManager.showArtificialHorizonView()) {
+ horizonView.visibility = View.VISIBLE
+ } else {
+ horizonView.visibility = View.GONE
+ }
}
private fun connect() {
@@ -405,6 +412,8 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, DataDecoder.Listen
speed.text = "-"
distance.text = "-"
mode.text = "Disconnected"
+ horizonView.setPitch(0f)
+ horizonView.setRoll(0f)
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
this.fuel.setCompoundDrawablesWithIntrinsicBounds(
ContextCompat.getDrawable(this, R.drawable.ic_battery_unknown),
@@ -508,14 +517,26 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, DataDecoder.Listen
}
override fun onRollData(rollAngle: Float) {
-
+ horizonView.setRoll(rollAngle)
}
override fun onPitchData(pitchAngle: Float) {
-
+ horizonView.setPitch(pitchAngle)
}
override fun onGSpeedData(speed: Float) {
+ if (!preferenceManager.usePitotTube()) {
+ updateSpeed(speed)
+ }
+ }
+
+ override fun onAirSpeed(speed: Float) {
+ if (preferenceManager.usePitotTube()) {
+ updateSpeed(speed)
+ }
+ }
+
+ private fun updateSpeed(speed: Float) {
this.speed.text = "${speed.roundToInt()} km/h"
}
@@ -708,7 +729,20 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, DataDecoder.Listen
}
override fun onFuelData(fuel: Int) {
- when (fuel) {
+ val batteryUnits = preferenceManager.getBatteryUnits()
+ var realFuel = fuel
+
+ when (batteryUnits) {
+ "mAh", "mWh" -> {
+ this.fuel.text = "$fuel $batteryUnits"
+ realFuel = ((1 - (4.2f - lastCellVoltage)).coerceIn(0f, 1f) * 100).toInt()
+ }
+ "Percentage" -> {
+ this.fuel.text = "$fuel%"
+ }
+ }
+
+ when (realFuel) {
in 91..100 -> R.drawable.ic_battery_full
in 81..90 -> R.drawable.ic_battery_90
in 61..80 -> R.drawable.ic_battery_80
@@ -732,8 +766,10 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback, DataDecoder.Listen
null,
null
)
- } }
- this.fuel.text = "$fuel%"
+ }
+ }
+
+
}
override fun onGPSData(list: List, addToEnd: Boolean) {
diff --git a/app/src/main/res/layout/activity_maps.xml b/app/src/main/res/layout/activity_maps.xml
index b0663268..283b7b23 100644
--- a/app/src/main/res/layout/activity_maps.xml
+++ b/app/src/main/res/layout/activity_maps.xml
@@ -36,6 +36,13 @@
layout="@layout/bottom_layout"
android:id="@+id/bottom_layout"/>
+
+
Connect
Disconnect
Disconnecting…
+
+
+ - Percentage
+ - mAh
+ - mWh
+
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 8f7db67d..cf75846b 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -37,5 +37,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file