1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-31 16:52:10 +01:00

Merge branch 'android' into revo-mini

Conflicts:
	androidgcs/AndroidManifest.xml
	androidgcs/res/layout/gcs_home.xml
	androidgcs/res/values/strings.xml
	androidgcs/src/org/openpilot/androidgcs/AttitudeView.java
	androidgcs/src/org/openpilot/androidgcs/HomePage.java
This commit is contained in:
James Cotton 2012-08-30 12:10:12 -05:00
commit 69328edd0d
32 changed files with 5902 additions and 4663 deletions

View File

@ -1,96 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.openpilot.androidgcs" android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="14" />
package="org.openpilot.androidgcs"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-sdk android:minSdkVersion="14" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.usb.host" />
<application android:icon="@drawable/ic_logo" android:label="@string/app_name" android:theme="@android:style/Theme.Holo">
<!-- for map overlay -->
<uses-library android:name="com.google.android.maps" />
<uses-feature android:glEsVersion="0x00020000" /> <!-- OpenGL min requierements (2.0) -->
<!-- Object browser - main activity at the moment -->
<activity android:name="HomePage" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- <intent-filter> -->
<!-- <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> -->
<!-- </intent-filter> -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" -->
<!-- android:resource="@xml/device_filter" /> -->
</activity>
<uses-feature android:name="android.hardware.usb.host" />
<activity android:name="ObjectBrowser" android:label="@string/object_browser_name" />
<activity android:name="PfdActivity" android:label="PFD" />
<activity android:name="Controller" android:label="@string/controller_name" />
<activity android:name="Preferences" android:label="@string/preference_title" />
<activity android:name="UAVLocation" android:label="@string/location_name" />
<activity android:name="SystemAlarmActivity" android:label="System Alarms" />
<activity android:name="TuningActivity" android:label="Tuning" />
<activity android:name="ObjectEditor" android:label="ObjectEditor"
android:theme="@android:style/Theme.Dialog" />
<activity android:name="Logger" android:label="Logger"
android:theme="@android:style/Theme.Dialog" />
<activity
android:name="FragmentTester"
android:label="FragmentTester" />
<application
android:icon="@drawable/ic_logo"
android:label="@string/app_name"
android:theme="@android:style/Theme.Holo" >
<!-- for map overlay -->
<uses-library android:name="com.google.android.maps" />
<!-- Object browser - main activity at the moment -->
<activity
android:name="org.openpilot.androidgcs.HomePage"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- <intent-filter> -->
<!-- <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> -->
<!-- </intent-filter> -->
<!-- <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" -->
<!-- android:resource="@xml/device_filter" /> -->
</activity>
<activity
android:name="ObjectBrowser"
android:label="@string/object_browser_name" />
<activity
android:name="PfdActivity"
android:label="PFD" />
<activity
android:name="Controller"
android:label="@string/controller_name" />
<activity
android:name="Preferences"
android:label="@string/preference_title" />
<activity
android:name="UAVLocation"
android:label="@string/location_name" />
<activity
android:name="SystemAlarmActivity"
android:label="System Alarms" />
<activity
android:name="ObjectEditor"
android:label="ObjectEditor"
android:theme="@android:style/Theme.Dialog" />
<activity
android:name="Logger"
android:label="Logger"
android:theme="@android:style/Theme.Dialog" />
<activity android:name="FragmentTester" android:label="FragmentTester" />
<activity
android:name="OsgViewer"
android:label="3DView" />
<receiver android:name="TelemetryWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<intent-filter>
<action android:name="org.openpilot.intent.action.CONNECTED" />
<action android:name="org.openpilot.intent.action.DISCONNECTED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/telemetry_widget_info" />
</receiver>
<service android:name="org.openpilot.androidgcs.telemetry.OPTelemetryService" >
</service>
</application>
<receiver android:name="TelemetryWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<intent-filter>
<action android:name="org.openpilot.intent.action.CONNECTED" />
<action android:name="org.openpilot.intent.action.DISCONNECTED" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/telemetry_widget_info" />
</receiver>
<service android:name="org.openpilot.androidgcs.telemetry.OPTelemetryService"></service>
</application>
</manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 823 B

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 800 B

After

Width:  |  Height:  |  Size: 797 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_gravity="center_horizontal" >
<Button
android:id="@+id/launch_controller"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_column="3"
android:layout_gravity="right"
android:layout_row="1"
android:layout_rowSpan="4"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_controller"
android:text="@string/controller_name" />
<Button
android:id="@+id/launch_object_browser"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_gravity="right|bottom"
android:layout_row="2"
android:layout_rowSpan="2"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_browser"
android:text="@string/object_browser_name" />
<Button
android:id="@+id/launch_location"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_column="2"
android:layout_gravity="right|bottom"
android:layout_row="2"
android:layout_rowSpan="2"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_map"
android:text="@string/location_name" />
<Button
android:id="@+id/launch_tuning"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_column="4"
android:layout_gravity="right|bottom"
android:layout_row="2"
android:layout_rowSpan="2"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_tuning"
android:text="@string/tuning" />
<Button
android:id="@+id/launch_logger"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_column="3"
android:layout_gravity="left|bottom"
android:layout_row="3"
android:layout_rowSpan="3"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_logging"
android:text="@string/logger_name" />
<Button
android:id="@+id/launch_alarms"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_gravity="left"
android:layout_row="5"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_alarms"
android:text="@string/alarms" />
<Button
android:id="@+id/launch_pfd"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_column="2"
android:layout_gravity="left"
android:layout_row="5"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_pfd"
android:text="@string/pfd_name" />
<Button
android:id="@+id/launch_osgViewer"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_gravity="right"
android:layout_row="9"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_alarms"
android:text="@string/_3dview" />
<Button
android:id="@+id/launch_tester"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_column="2"
android:layout_row="9"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_alarms"
android:text="@string/tester" />
<Space
android:layout_width="1dp"
android:layout_height="32dp"
android:layout_column="0"
android:layout_row="0" />
<Space
android:layout_width="1dp"
android:layout_height="47dp"
android:layout_column="0"
android:layout_row="4" />
<Space
android:layout_width="1dp"
android:layout_height="47dp"
android:layout_column="0"
android:layout_row="8" />
<Space
android:layout_height="15dp"
android:layout_column="1" />
<Space
android:layout_width="100dp"
android:layout_height="2dp"
android:layout_row="6" />
</GridLayout>

View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:setting_attributes="http://schemas.android.com/apk/res/org.openpilot.androidgcs"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/saveBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="@string/save" />
<Button
android:id="@+id/applyBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@+id/saveBtn"
android:text="@string/apply" />
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" >
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/rollRateKp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
setting_attributes:max_value="0.01"
setting_attributes:setting_name="Roll Rate Kp" >
</org.openpilot.androidgcs.views.ScrollBarView>
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/pitchRateKp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
setting_attributes:max_value="0.01"
setting_attributes:setting_name="Pitch Rate Kp" >
</org.openpilot.androidgcs.views.ScrollBarView>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/linearLayout3" >
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/rollRateKi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
setting_attributes:max_value="0.05"
setting_attributes:setting_name="Roll Rate Ki" >
</org.openpilot.androidgcs.views.ScrollBarView>
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/pitchRateKi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
setting_attributes:max_value="0.05"
setting_attributes:setting_name="Pitch Rate Ki" >
</org.openpilot.androidgcs.views.ScrollBarView>
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/linearLayout1" >
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/rollKp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
setting_attributes:max_value="5"
setting_attributes:setting_name="Roll Kp" >
</org.openpilot.androidgcs.views.ScrollBarView>
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/pitchKp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
setting_attributes:max_value="5"
setting_attributes:setting_name="Pitch Kp" >
</org.openpilot.androidgcs.views.ScrollBarView>
</LinearLayout>
</RelativeLayout>

View File

@ -81,25 +81,37 @@
android:id="@+id/launch_tester"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_row="6"
android:layout_row="8"
android:layout_column="0"
android:layout_rowSpan="2"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_alarms"
android:text="@string/tester" />
<Button
android:id="@+id/launch_osgViewer"
<Button
android:id="@+id/launch_osgViewer"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_column="1"
android:layout_gravity="right"
android:layout_row="8"
android:layout_rowSpan="2"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_alarms"
android:text="@string/_3dview" />
<Button
android:id="@+id/launch_tuning"
android:layout_width="132dp"
android:layout_height="wrap_content"
android:layout_column="1"
android:layout_column="0"
android:layout_gravity="right"
android:layout_row="6"
android:layout_rowSpan="2"
android:background="@android:color/transparent"
android:drawableTop="@drawable/ic_alarms"
android:text="@string/_3dview" />
android:drawableTop="@drawable/ic_tuning"
android:text="@string/tuning" />
<Space
android:layout_width="1dp"
android:layout_height="32dp"

View File

@ -23,14 +23,14 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="Settings" />
android:text="@string/settings" />
<CheckBox
android:id="@+id/dataCheck"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="Data" />
android:text="@string/data" />
</LinearLayout>
@ -56,7 +56,7 @@
android:layout_height="fill_parent"
android:background="#FFFFFFFF" />
<LinearLayout
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
@ -66,40 +66,29 @@
android:id="@+id/object_information"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="12dp"
android:layout_marginTop="12dp"
android:textAppearance="?android:attr/textAppearanceMedium" />
<Space
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/editButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="@string/edit" />
<Space
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/object_load_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@+id/editButton"
android:text="@string/load" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</RelativeLayout>
<Button
android:id="@+id/object_load_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Load" />
<Button
android:id="@+id/editButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginBottom="32dp"
android:layout_marginRight="12dp"
android:text="Edit" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:setting_attributes="http://schemas.android.com/apk/res/org.openpilot.androidgcs"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/rollRateKp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
setting_attributes:setting_name="Roll Rate Kp"
setting_attributes:max_value="0.01" />
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/pitchRateKp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
setting_attributes:setting_name="Pitch Rate Kp"
setting_attributes:max_value="0.01" />
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/rollRateKi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
setting_attributes:setting_name="Roll Rate Ki"
setting_attributes:max_value="0.05" />
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/pitchRateKi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
setting_attributes:setting_name="Pitch Rate Ki"
setting_attributes:max_value="0.05" />
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/rollKp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
setting_attributes:setting_name="Roll Kp"
setting_attributes:max_value="5" />
<org.openpilot.androidgcs.views.ScrollBarView
android:id="@+id/pitchKp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
setting_attributes:setting_name="Pitch Kp"
setting_attributes:max_value="5" />
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right" >
<Button
android:id="@+id/applyBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/apply" />
<Button
android:id="@+id/saveBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/save" />
</LinearLayout>
</LinearLayout>

View File

@ -14,4 +14,12 @@
<item>3</item>
<item>4</item>
</string-array>
<string-array name="controllerTypeArray">
<item>Mode 1</item>
<item>Mode 2</item>
</string-array>
<string-array name="controllerTypeValues">
<item>1</item>
<item>2</item>
</string-array>
</resources>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="setting_attributes">
<attr name="setting_name" format="string"/>
<attr name="max_value" format="float"/>
</declare-styleable>
</resources>

View File

@ -34,4 +34,11 @@
<string name="rxrate">RxRate: </string>
<string name="tester">Tester</string>
<string name="_3dview">3DView</string>
<string name="tuning">Tuning</string>
<string name="apply">Apply</string>
<string name="save">Save</string>
<string name="settings">Settings</string>
<string name="data">Data</string>
<string name="edit">Edit</string>
<string name="load">Load</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory android:title="Controller Settings">
<ListPreference android:title="Controller Mode"
android:key="controller_type" android:summary="Select whether you want the virtual controller to use mode 1 or mode 2 convention"
android:defaultValue="Mode 1"
android:entries="@array/controllerTypeArray"
android:entryValues="@array/controllerTypeValues"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@ -56,29 +56,64 @@ public class AttitudeView extends View {
}
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredWidth = measure(widthMeasureSpec);
int measuredHeight = measure(heightMeasureSpec);
int d = Math.min(measuredWidth, measuredHeight);
setMeasuredDimension(d/2, d/2);
}
/**
* @see android.view.View#measure(int, int)
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),
measureHeight(heightMeasureSpec));
}
private int measure(int measureSpec) {
int result = 0;
// Decode the measurement specifications.
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
/**
* Determines the height of this view
* @param measureSpec A measureSpec packed into an int
* @return The height of the view, honoring constraints from measureSpec
*/
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.UNSPECIFIED) { // Return a default size of 200 if no bounds are specified.
result = 200;
} else {
// As you want to fill the available space
// always return the full available bounds.
result = specSize;
}
return result;
}
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = 1600;
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by measureSpec
result = Math.min(result, specSize);
}
}
return result;
}
/**
* Determines the width of this view
* @param measureSpec A measureSpec packed into an int
* @return The width of the view, honoring constraints from measureSpec
*/
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = 800;
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by measureSpec
result = Math.min(result, specSize);
}
}
return result;
}
private float roll;
public void setRoll(double roll) {
@ -101,25 +136,35 @@ public class AttitudeView extends View {
canvas.save();
canvas.rotate(-roll, PX / 2, PY / 2);
canvas.save();
canvas.translate(0, pitch * DEG_TO_PX);
Drawable horizon = getContext().getResources().getDrawable(
R.drawable.im_pfd_horizon);
Drawable reticule = getContext().getResources().getDrawable(
R.drawable.im_pfd_reticule);
Drawable fixed = getContext().getResources().getDrawable(
R.drawable.im_pfd_fixed);
// Starting with a square image, want to size it equally
double margin = 0.2;
int screenSize = Math.min(PX, PY);
int imageHalfSize = (int) ((screenSize + screenSize * margin) / 2);
// This puts the image at the center of the PFD canvas (after it was
// translated)
double margin = 0.5;
horizon.setBounds( (int) (-margin * PX), (int) (-margin * PY), (int) ((1 + margin) * PX), (int) ((1+margin) *PY));
horizon.setBounds( PX/2 - imageHalfSize, PY/2 - imageHalfSize, PX/2 + imageHalfSize, PY/2 + imageHalfSize);
horizon.draw(canvas);
canvas.restore();
canvas.drawLine(0, 0, PX, 0, markerPaint);
canvas.drawLine(0, 0, 0, PY, markerPaint);
canvas.drawLine(PX, 0, PX, PY, markerPaint);
canvas.drawLine(0, PY, PX, PY, markerPaint);
// Draw the overlay that only rolls
reticule.setBounds( PX/2 - imageHalfSize, PY/2 - imageHalfSize, PX/2 + imageHalfSize, PY/2 + imageHalfSize);
reticule.draw(canvas);
canvas.restore();
canvas.drawLine(0,PY/2,PX,PY/2,markerPaint);
canvas.drawLine(PX/2,0,PX/2,PY,markerPaint);
}
// Draw the overlay that never moves
fixed.setBounds( PX/2 - imageHalfSize, PY/2 - imageHalfSize, PX/2 + imageHalfSize, PY/2 + imageHalfSize);
fixed.draw(canvas);
}
}

View File

@ -44,10 +44,7 @@ public class BluetoothDevicePreference extends ListPreference {
Set<BluetoothDevice> pairedDevices = bta.getBondedDevices();
CharSequence[] entries = new CharSequence[pairedDevices.size()];
CharSequence[] entryValues = new CharSequence[pairedDevices.size()];
if (pairedDevices.size() == 0) {
entries[0] = "No Devices";
entryValues[0] = "";
} else {
if (pairedDevices.size() > 0) {
int i = 0;
for (BluetoothDevice dev : pairedDevices) {
entries[i] = dev.getName();

View File

@ -34,7 +34,9 @@ import org.openpilot.uavtalk.UAVDataObject;
import org.openpilot.uavtalk.UAVObject;
import org.openpilot.uavtalk.UAVObjectField;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
@ -76,7 +78,7 @@ public class Controller extends ObjectManagerActivity {
@Override
public void update(Observable observable, Object data) {
// Once we have updated settings we can active the GCS receiver mode
Log.d(TAG,"Got update from settings");
if (DEBUG) Log.d(TAG,"Got update from settings");
UAVDataObject manualControlSettings = (UAVDataObject) objMngr.getObject("ManualControlSettings");
if(manualControlSettings != null) {
manualControlSettings.removeUpdatedObserver(this);
@ -89,7 +91,27 @@ public class Controller extends ObjectManagerActivity {
void onOPConnected() {
super.onOPConnected();
Log.d(TAG, "onOPConnected()");
if (DEBUG) Log.d(TAG, "onOPConnected()");
DualJoystickView joystick = (DualJoystickView) findViewById(R.id.dualjoystickView);
joystick.setMovementConstraint(JoystickView.CONSTRAIN_BOX);
joystick.setMovementRange((int)MOVEMENT_RANGE, (int)MOVEMENT_RANGE);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int mode = Integer.decode(prefs.getString("controller_type", "1"));
switch(mode) {
case 1:
if (DEBUG) Log.d(TAG, "Mode1 connected");
joystick.setOnJostickMovedListener(mode1_left, mode1_right);
break;
case 2:
if (DEBUG) Log.d(TAG, "Mode2 connected");
joystick.setOnJostickMovedListener(mode2_left, mode2_right);
break;
default:
Log.e(TAG, "Unknown controller type");
return;
}
// Subscribe to updates from ManualControlCommand and show the values for crude feedback
UAVDataObject manualControl = (UAVDataObject) objMngr.getObject("ManualControlCommand");
@ -100,39 +122,6 @@ public class Controller extends ObjectManagerActivity {
manualSettings.addUpdatedObserver(settingsUpdated);
manualSettings.updateRequested();
final double MOVEMENT_RANGE = 50.0;
DualJoystickView joystick = (DualJoystickView) findViewById(R.id.dualjoystickView);
joystick.setMovementConstraint(JoystickView.CONSTRAIN_BOX);
joystick.setMovementRange((int)MOVEMENT_RANGE, (int)MOVEMENT_RANGE);
// Hardcode a Mode 1 listener for now
joystick.setOnJostickMovedListener(new JoystickMovedListener() {
@Override
public void OnMoved(int pan, int tilt) {
pitch = tilt / MOVEMENT_RANGE;
yaw = pan / MOVEMENT_RANGE;
leftJoystickHeld = true;
}
@Override
public void OnReleased() { leftJoystickHeld = false; throttle = -1; updated = true; }
@Override
public void OnReturnedToCenter() { }
}, new JoystickMovedListener() {
@Override
public void OnMoved(int pan, int tilt) {
throttle = (-tilt + (MOVEMENT_RANGE -5)) / (MOVEMENT_RANGE - 5);
throttle *= 0.5;
if (throttle < 0)
throttle = -1;
roll = pan / MOVEMENT_RANGE;
rightJoystickHeld = true;
}
@Override
public void OnReleased() { rightJoystickHeld = false; throttle = -1; updated = true; }
@Override
public void OnReturnedToCenter() { }
});
//! This timer task actually periodically sends updates to the UAV
TimerTask controllerTask = new TimerTask() {
@Override
@ -248,4 +237,64 @@ public class Controller extends ObjectManagerActivity {
return (float) (neutral + (neutral - CHANNEL_MIN) * in);
}
private final JoystickMovedListener mode1_left = new JoystickMovedListener() {
@Override
public void OnMoved(int pan, int tilt) {
pitch = tilt / MOVEMENT_RANGE;
yaw = pan / MOVEMENT_RANGE;
leftJoystickHeld = true;
}
@Override
public void OnReleased() { leftJoystickHeld = false; throttle = -1; updated = true; }
@Override
public void OnReturnedToCenter() { }
};
private final JoystickMovedListener mode1_right = new JoystickMovedListener() {
@Override
public void OnMoved(int pan, int tilt) {
throttle = (-tilt + (MOVEMENT_RANGE -5)) / (MOVEMENT_RANGE - 5);
throttle *= 0.5;
if (throttle < 0)
throttle = -1;
roll = pan / MOVEMENT_RANGE;
rightJoystickHeld = true;
}
@Override
public void OnReleased() { rightJoystickHeld = false; throttle = -1; updated = true; }
@Override
public void OnReturnedToCenter() { }
};
private final JoystickMovedListener mode2_left = new JoystickMovedListener() {
@Override
public void OnMoved(int pan, int tilt) {
throttle = (-tilt + (MOVEMENT_RANGE -5)) / (MOVEMENT_RANGE - 5);
throttle *= 0.5;
if (throttle < 0)
throttle = -1;
yaw = pan / MOVEMENT_RANGE;
leftJoystickHeld = true;
}
@Override
public void OnReleased() { leftJoystickHeld = false; throttle = -1; updated = true; }
@Override
public void OnReturnedToCenter() { }
};
private final JoystickMovedListener mode2_right = new JoystickMovedListener() {
@Override
public void OnMoved(int pan, int tilt) {
pitch = tilt / MOVEMENT_RANGE;
roll = pan / MOVEMENT_RANGE;
rightJoystickHeld = true;
}
@Override
public void OnReleased() { rightJoystickHeld = false; throttle = -1; updated = true; }
@Override
public void OnReturnedToCenter() { }
};
final double MOVEMENT_RANGE = 50.0;
}

View File

@ -91,6 +91,7 @@ public class HomePage extends ObjectManagerActivity {
startActivity(new Intent(HomePage.this, FragmentTester.class));
}
});
Button osgViewer = (Button) findViewById(R.id.launch_osgViewer);
osgViewer.setOnClickListener(new OnClickListener() {
@Override
@ -99,6 +100,14 @@ public class HomePage extends ObjectManagerActivity {
}
});
Button tuning = (Button) findViewById(R.id.launch_tuning);
tuning.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
startActivity(new Intent(HomePage.this, TuningActivity.class));
}
});
}
}

View File

@ -42,6 +42,7 @@ public class Preferences extends PreferenceActivity {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
addPreferencesFromResource(R.xml.controller_preferences);
}
}
}

View File

@ -0,0 +1,47 @@
package org.openpilot.androidgcs;
import org.openpilot.androidgcs.util.SmartSave;
import org.openpilot.androidgcs.views.ScrollBarView;
import org.openpilot.uavtalk.UAVDataObject;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
public class TuningActivity extends ObjectManagerActivity {
private final String TAG = TuningActivity.class.getSimpleName();
private final boolean DEBUG = false;
private SmartSave smartSave;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tuning);
}
@Override
void onOPConnected() {
super.onOPConnected();
if (DEBUG) Log.d(TAG, "onOPConnected()");
// Subscribe to updates from ManualControlCommand and show the values for crude feedback
UAVDataObject stabilizationSettings = (UAVDataObject) objMngr.getObject("StabilizationSettings");
smartSave = new SmartSave(objMngr, stabilizationSettings,
(Button) findViewById(R.id.saveBtn),
(Button) findViewById(R.id.applyBtn));
smartSave.addControlMapping((ScrollBarView) findViewById(R.id.rollRateKp), "RollRatePID", 0);
smartSave.addControlMapping((ScrollBarView) findViewById(R.id.rollRateKi), "RollRatePID", 1);
smartSave.addControlMapping((ScrollBarView) findViewById(R.id.pitchRateKp), "PitchRatePID", 0);
smartSave.addControlMapping((ScrollBarView) findViewById(R.id.pitchRateKi), "PitchRatePID", 1);
smartSave.addControlMapping((ScrollBarView) findViewById(R.id.rollKp), "RollPI", 0);
smartSave.addControlMapping((ScrollBarView) findViewById(R.id.pitchKp), "PitchPI", 0);
smartSave.refreshSettingsDisplay();
}
}

View File

@ -0,0 +1,6 @@
package org.openpilot.androidgcs.util;
public interface ObjectFieldMappable {
public double getValue();
public void setValue(double val);
}

View File

@ -0,0 +1,256 @@
/**
******************************************************************************
* @file SmartSave.java
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief Provides a handler to provide robust apply and save for settings
* and updating of the UI when the object changes.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.openpilot.androidgcs.util;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import junit.framework.Assert;
import org.openpilot.uavtalk.UAVObject;
import org.openpilot.uavtalk.UAVObjectManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class SmartSave {
private final static String TAG = SmartSave.class.getSimpleName();
private final static boolean DEBUG = false;
//! Create a smart save button attached to the object manager and an apply and ave button
public SmartSave(UAVObjectManager objMngr, UAVObject obj, Button saveButton, Button applyButton) {
Assert.assertNotNull(objMngr);
this.objMngr = objMngr;
this.applyBtn = applyButton;
this.obj = obj;
Assert.assertNotNull(objMngr);
Assert.assertNotNull(obj);
obj.addUpdatedObserver(ObjectUpdated);
controlFieldMapping = new HashMap<ObjectFieldMappable,FieldPairing>();
if (saveButton != null) {
saveBtn = saveButton;
saveBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
saveSettings();
}
});
} else
saveBtn = null;
if (applyButton != null) {
applyBtn = applyButton;
applyBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
applySettings();
}
});
} else
applyBtn = null;
}
//! Disconnect any listeners when this object is destroyed
public void disconnect() {
obj.removeUpdatedObserver(ObjectUpdated);
}
/**
* Add a control to this SmartSave object which maps between a particular control
* and a UAVO field.
* @param control The control to associate with
* @param fieldName The name of the UAVO field
* @param fieldIndex The index of the UAVO field
*/
public void addControlMapping(ObjectFieldMappable control, String fieldName, int fieldIndex) {
FieldPairing pairing = new FieldPairing(fieldName, fieldIndex);
controlFieldMapping.put(control, pairing);
}
//! Update the settings in the UI from the mappings
public void refreshSettingsDisplay() {
if (DEBUG) Log.d(TAG, "Refreshing display");
Set<ObjectFieldMappable> keys = controlFieldMapping.keySet();
Iterator<ObjectFieldMappable> iter = keys.iterator();
while(iter.hasNext()) {
ObjectFieldMappable mappable = iter.next();
FieldPairing field = controlFieldMapping.get(mappable);
mappable.setValue(field.getValue(obj));
}
}
/**
* Call applySettings() and then save them
* @return True if the save succeeded or false otherwise
*/
private boolean saveSettings() {
/*
* 1. Update object
* 2. Install listener on object persistence
* 3. Send save operation
* 4. Wait for completed
* 5. Remove listener
*/
// 1. Update object
if(!applySettings())
return false;
UAVObject persistence = objMngr.getObject("ObjectPersistence");
Assert.assertNotNull(persistence);
// 2. Install listener
persistence.addUpdatedObserver(ObjectPersistenceUpdated);
// 3. Send save operation
Long objId = obj.getObjID();
if (DEBUG) Log.d(TAG, "Saving object ID: " + objId);
persistence.getField("ObjectID").setValue(objId);
persistence.getField("Operation").setValue("Save");
persistence.getField("Selection").setValue("SingleObject");
persistence.updated();
return true;
}
/**
* Robustly apply the settings to the UAV
* @return True if the apply is ack'd, False if not
*/
private boolean applySettings() {
/*
* 1. Set the values from the fields into the object
* 2. Install the listener on the object
* 3. Update object
* 4. Wait for the acknowledgment or timeout
* 5. Uninstall the listener
*/
// 1. Set the fields in the object from the UI
Set<ObjectFieldMappable> keys = controlFieldMapping.keySet();
Iterator<ObjectFieldMappable> iter = keys.iterator();
while(iter.hasNext()) {
ObjectFieldMappable mappable = iter.next();
FieldPairing field = controlFieldMapping.get(mappable);
field.setValue(obj,mappable.getValue());
}
// 2. Install the listener on the object
obj.addTransactionCompleted(ApplyCompleted);
// 3. Update the object
obj.updated();
// 4. Wait for acknowledgment
// TODO: Set up some semaphore with timeout
// sem.wait(1000);
// 5. Uninstall the listener
//obj.removeTransactionCompleted(ApplyCompleted);
return true;
}
//! Private class to store the field mapping information
private class FieldPairing {
FieldPairing(String fieldName, int fieldIndex) {
this.fieldName = fieldName;
this.fieldIndex = fieldIndex;
}
//! Update the field in the UAVO
void setValue(UAVObject obj, double value) {
Assert.assertNotNull(obj);
obj.getField(fieldName).setDouble(value,fieldIndex);
}
//! Get the value from the UAVO field
double getValue(UAVObject obj) {
double val = obj.getField(fieldName).getDouble(fieldIndex);
if (DEBUG) Log.d(TAG, "Getting value from: " + fieldName + " " + val);
return obj.getField(fieldName).getDouble(fieldIndex);
}
//! Cache the name of the field
private final String fieldName;
//! Cache the field index
private final int fieldIndex;
}
//! Installed on monitored object to know when an object is updated
private final Observer ApplyCompleted = new Observer() {
@Override
public void update(Observable observable, Object data) {
if (DEBUG) Log.d(TAG, "Apply called");
}
};
//! Installed on monitored object to know when an object is updated
private final Observer ObjectUpdated = new Observer() {
@Override
public void update(Observable observable, Object data) {
if (DEBUG) Log.d(TAG, "Object updated");
refreshSettingsDisplay();
}
};
//! Installed on object persistence to know when save completes
private final Observer ObjectPersistenceUpdated = new Observer() {
@Override
public void update(Observable observable, Object data) {
if (DEBUG) Log.d(TAG, "Object persistence updated");
}
};
//! Map of all the UAVO field <-> control mappings. The key is the control.
private final Map<ObjectFieldMappable,FieldPairing> controlFieldMapping;
//! Handle to the object manager
private final UAVObjectManager objMngr;
//! Handle to the apply button
private Button applyBtn;
//! Handle to the save button
private Button saveBtn;
//! Handle to the UAVO this class works with
private final UAVObject obj;
}

View File

@ -0,0 +1,129 @@
package org.openpilot.androidgcs.views;
import org.openpilot.androidgcs.R;
import org.openpilot.androidgcs.util.ObjectFieldMappable;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.EditText;
import android.widget.GridLayout;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
public class ScrollBarView extends GridLayout implements ObjectFieldMappable {
private final static String TAG = ScrollBarView.class.getSimpleName();
private final TextView lbl;
private final EditText edit;
private final SeekBar bar;
private double value;
private String name;
private final double SCALE = 1000000;
public ScrollBarView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(TAG, "Scroll bar init called");
setOrientation(LinearLayout.VERTICAL);
setColumnCount(2);
lbl = new TextView(context);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.setting_attributes, 0, 0);
lbl.setText(ta.getString(R.styleable.setting_attributes_setting_name));
addView(lbl, new GridLayout.LayoutParams(spec(0), spec(0)));
edit = new EditText(context);
addView(edit, new GridLayout.LayoutParams(spec(0), spec(1)));
bar = new SeekBar(context);
addView(bar, new GridLayout.LayoutParams(spec(1), spec(0,2)));
ta = context.obtainStyledAttributes(attrs, R.styleable.setting_attributes, 0, 0);
final double max = ta.getFloat(R.styleable.setting_attributes_max_value,0);
bar.setMax((int) (SCALE * max));
// Update the value when the progress bar changes
bar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
value = progress / SCALE;
edit.setText(Double.toString(value));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
// Update the value when the edit box changes
edit.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
value = Double.parseDouble(s.toString());
bar.setProgress((int) (SCALE * value));
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
});
setPadding(5,5,5,5);
setMinimumWidth(300);
setValue(0.0035);
}
public void setName(String n)
{
name = n;
lbl.setText(name);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// This shouldn't be needed if I could make this scroll bar
// automagically span both columns
android.view.ViewGroup.LayoutParams param = bar.getLayoutParams();
param.width = (int) (getMeasuredWidth() * 0.9);
// Force the label to half the page width
param = lbl.getLayoutParams();
param.width = getMeasuredWidth() / 2;
}
@Override
public double getValue() {
return value;
}
@Override
public void setValue(double val) {
value = val;
edit.setText(Double.toString(value));
bar.setProgress((int) (SCALE * value));
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 823 B

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB