mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-29 14:52:12 +01:00
Merge branch 'android' into sim_android
Conflicts: androidgcs/AndroidManifest.xml androidgcs/res/layout/gcs_home.xml androidgcs/res/layout/pfd.xml androidgcs/res/layout/system_alarms.xml androidgcs/src/org/openpilot/androidgcs/AttitudeView.java androidgcs/src/org/openpilot/androidgcs/BluetoothDevicePreference.java androidgcs/src/org/openpilot/androidgcs/CompassView.java androidgcs/src/org/openpilot/androidgcs/Controller.java androidgcs/src/org/openpilot/androidgcs/HomePage.java androidgcs/src/org/openpilot/androidgcs/Logger.java androidgcs/src/org/openpilot/androidgcs/ObjectBrowser.java androidgcs/src/org/openpilot/androidgcs/ObjectEditor.java androidgcs/src/org/openpilot/androidgcs/ObjectManagerActivity.java androidgcs/src/org/openpilot/androidgcs/Preferences.java androidgcs/src/org/openpilot/androidgcs/SystemAlarmActivity.java androidgcs/src/org/openpilot/androidgcs/TelemetryWidget.java androidgcs/src/org/openpilot/androidgcs/UAVLocation.java androidgcs/src/org/openpilot/uavtalk/Telemetry.java androidgcs/src/org/openpilot/uavtalk/TelemetryMonitor.java androidgcs/src/org/openpilot/uavtalk/UAVDataObject.java androidgcs/src/org/openpilot/uavtalk/UAVMetaObject.java androidgcs/src/org/openpilot/uavtalk/UAVObject.java androidgcs/src/org/openpilot/uavtalk/UAVObjectField.java androidgcs/src/org/openpilot/uavtalk/UAVObjectManager.java androidgcs/src/org/openpilot/uavtalk/UAVTalk.java androidgcs/src/org/openpilot/uavtalk/uavobjects/AltitudeHoldSettings.java androidgcs/src/org/openpilot/uavtalk/uavobjects/FirmwareIAPObj.java androidgcs/src/org/openpilot/uavtalk/uavobjects/FlightBatterySettings.java androidgcs/src/org/openpilot/uavtalk/uavobjects/FlightBatteryState.java androidgcs/src/org/openpilot/uavtalk/uavobjects/FlightStatus.java androidgcs/src/org/openpilot/uavtalk/uavobjects/HomeLocation.java androidgcs/src/org/openpilot/uavtalk/uavobjects/HwSettings.java androidgcs/src/org/openpilot/uavtalk/uavobjects/ManualControlSettings.java androidgcs/src/org/openpilot/uavtalk/uavobjects/OveroSyncStats.java androidgcs/src/org/openpilot/uavtalk/uavobjects/PositionActual.java androidgcs/src/org/openpilot/uavtalk/uavobjects/RevoCalibration.java androidgcs/src/org/openpilot/uavtalk/uavobjects/SystemAlarms.java androidgcs/src/org/openpilot/uavtalk/uavobjects/TaskInfo.java androidgcs/src/org/openpilot/uavtalk/uavobjects/UAVObjectsInitialize.java flight/Modules/GPS/GPS.c
This commit is contained in:
commit
f530702ce9
@ -1,5 +1,13 @@
|
||||
Short summary of changes. For a complete list see the git log.
|
||||
|
||||
2012-07-20
|
||||
AeroSimRC simulator plugin is now included into the Windows distribution
|
||||
(will be installed into .../OpenPilot/misc/AeroSIM-RC directory). Still
|
||||
being an experimental development tool, it could be used to play with
|
||||
HITL version 2. Other platforms include udp_test utility which can be
|
||||
used to check the connectivity with AeroSimRC plugin running on Windows
|
||||
machine.
|
||||
|
||||
2012-07-10
|
||||
On Windows the installation mode was changed from per-user to per-machine
|
||||
(for all users) installation. It is recommended to completely uninstall
|
||||
|
@ -24,7 +24,7 @@
|
||||
</activity>
|
||||
|
||||
<activity android:name="ObjectBrowser" android:label="@string/object_browser_name" />
|
||||
<activity android:name="PFD" android:label="PFD" />
|
||||
<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" />
|
||||
@ -46,6 +46,6 @@
|
||||
android:resource="@xml/telemetry_widget_info" />
|
||||
</receiver>
|
||||
|
||||
<service android:name=".OPTelemetryService"></service>
|
||||
<service android:name="org.openpilot.androidgcs.telemetry.OPTelemetryService"></service>
|
||||
</application>
|
||||
</manifest>
|
BIN
androidgcs/res/drawable-hdpi/im_pfd_horizon.png
Normal file
BIN
androidgcs/res/drawable-hdpi/im_pfd_horizon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
@ -33,9 +33,9 @@
|
||||
android:id="@+id/launch_pfd"
|
||||
android:layout_width="132dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_column="2"
|
||||
android:layout_column="0"
|
||||
android:layout_gravity="center"
|
||||
android:layout_row="0"
|
||||
android:layout_row="2"
|
||||
android:layout_rowSpan="2"
|
||||
android:background="@android:color/transparent"
|
||||
android:drawableTop="@drawable/ic_pfd"
|
||||
@ -45,7 +45,7 @@
|
||||
android:id="@+id/launch_controller"
|
||||
android:layout_width="132dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_column="0"
|
||||
android:layout_column="1"
|
||||
android:layout_gravity="right"
|
||||
android:layout_row="2"
|
||||
android:layout_rowSpan="2"
|
||||
@ -57,9 +57,9 @@
|
||||
android:id="@+id/launch_logger"
|
||||
android:layout_width="132dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_column="1"
|
||||
android:layout_column="0"
|
||||
android:layout_gravity="right"
|
||||
android:layout_row="2"
|
||||
android:layout_row="4"
|
||||
android:layout_rowSpan="2"
|
||||
android:background="@android:color/transparent"
|
||||
android:drawableTop="@drawable/ic_logging"
|
||||
@ -69,9 +69,9 @@
|
||||
android:id="@+id/launch_alarms"
|
||||
android:layout_width="132dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_column="2"
|
||||
android:layout_column="1"
|
||||
android:layout_gravity="right"
|
||||
android:layout_row="2"
|
||||
android:layout_row="4"
|
||||
android:layout_rowSpan="2"
|
||||
android:background="@android:color/transparent"
|
||||
android:drawableTop="@drawable/ic_alarms"
|
||||
|
@ -3,14 +3,10 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<org.openpilot.androidgcs.CompassView
|
||||
android:id="@+id/compass_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<org.openpilot.androidgcs.AttitudeView
|
||||
android:id="@+id/attitude_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -4,11 +4,16 @@
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center" >
|
||||
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/system_alarms_status"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center" />
|
||||
<fragment
|
||||
android:name="org.openpilot.androidgcs.fragments.SystemAlarmsFragment"
|
||||
android:id="@+id/viewer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
<fragment
|
||||
android:name="org.openpilot.androidgcs.fragments.PFD"
|
||||
android:id="@+id/pfd"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
18
androidgcs/res/layout/system_alarms_fragment.xml
Normal file
18
androidgcs/res/layout/system_alarms_fragment.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar3"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/system_alarms_fragment_field"
|
||||
android:layout_width="200dip"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
@ -1,89 +1,117 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file AttitudeView.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief A view for UAV attitude.
|
||||
* @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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
public class AttitudeView extends View {
|
||||
|
||||
private Paint markerPaint;
|
||||
public AttitudeView(Context context) {
|
||||
super(context);
|
||||
initAttitudeView();
|
||||
}
|
||||
|
||||
public AttitudeView(Context context, AttributeSet ats, int defaultStyle) {
|
||||
public AttitudeView(Context context, AttributeSet ats, int defaultStyle) {
|
||||
super(context, ats, defaultStyle);
|
||||
initAttitudeView();
|
||||
}
|
||||
|
||||
public AttitudeView(Context context, AttributeSet ats) {
|
||||
public AttitudeView(Context context, AttributeSet ats) {
|
||||
super(context, ats);
|
||||
initAttitudeView();
|
||||
}
|
||||
|
||||
protected void initAttitudeView() {
|
||||
protected void initAttitudeView() {
|
||||
setFocusable(true);
|
||||
markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
markerPaint.setColor(getContext().getResources().getColor(
|
||||
R.color.marker_color));
|
||||
|
||||
circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
circlePaint.setColor(R.color.background_color);
|
||||
circlePaint.setStrokeWidth(1);
|
||||
circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
Resources r = this.getResources();
|
||||
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
textPaint.setColor(r.getColor(R.color.text_color));
|
||||
markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
markerPaint.setColor(r.getColor(R.color.marker_color));
|
||||
}
|
||||
|
||||
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int measuredWidth = measure(widthMeasureSpec);
|
||||
int measuredWidth = measure(widthMeasureSpec);
|
||||
int measuredHeight = measure(heightMeasureSpec);
|
||||
int d = Math.min(measuredWidth, measuredHeight);
|
||||
int d = Math.min(measuredWidth, measuredHeight);
|
||||
setMeasuredDimension(d/2, d/2);
|
||||
}
|
||||
|
||||
private int measure(int measureSpec) {
|
||||
private int measure(int measureSpec) {
|
||||
int result = 0;
|
||||
// Decode the measurement specifications.
|
||||
// Decode the measurement specifications.
|
||||
|
||||
int specMode = MeasureSpec.getMode(measureSpec);
|
||||
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.
|
||||
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.
|
||||
} else {
|
||||
// As you want to fill the available space
|
||||
// always return the full available bounds.
|
||||
result = specSize;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private double roll;
|
||||
public void setRoll(double roll) {
|
||||
this.roll = roll;
|
||||
}
|
||||
private double pitch;
|
||||
public void setPitch(double d) {
|
||||
this.pitch = d;
|
||||
}
|
||||
private float roll;
|
||||
public void setRoll(double roll) {
|
||||
this.roll = (float) roll;
|
||||
}
|
||||
|
||||
// Drawing related code
|
||||
private Paint markerPaint;
|
||||
private Paint textPaint;
|
||||
private Paint circlePaint;
|
||||
private float pitch;
|
||||
public void setPitch(double d) {
|
||||
this.pitch = (float) d;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
int px = getMeasuredWidth() / 2;
|
||||
int py = getMeasuredHeight() /2 ;
|
||||
int radius = Math.min(px, py);
|
||||
|
||||
canvas.drawLine(px,py, (int) (px+radius * Math.cos(roll)), (int) (py + radius * Math.sin(roll)), markerPaint);
|
||||
canvas.drawLine(px,py, (int) (px+radius * Math.cos(pitch)), (int) (py + radius * Math.sin(pitch)), markerPaint);
|
||||
|
||||
final int PX = getMeasuredWidth() / 2;
|
||||
final int PY = getMeasuredHeight() / 2;
|
||||
|
||||
// TODO: Figure out why these magic numbers are needed to center it
|
||||
final int WIDTH = 600;
|
||||
final int HEIGHT = 600;
|
||||
final int DEG_TO_PX = 10; // Magic number for how to scale pitch
|
||||
|
||||
canvas.save(0);
|
||||
canvas.rotate(-roll, PX, PY);
|
||||
canvas.translate(0, pitch * DEG_TO_PX);
|
||||
Drawable horizon = getContext().getResources().getDrawable(
|
||||
R.drawable.im_pfd_horizon);
|
||||
// This puts the image at the center of the PFD canvas (after it was
|
||||
// translated)
|
||||
horizon.setBounds(-(WIDTH - PX) / 2, -(HEIGHT - PY) / 2, WIDTH, HEIGHT);
|
||||
horizon.draw(canvas);
|
||||
canvas.restore();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,26 +1,59 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file BluetoothDevicePreference.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief A dialog in the preferences options that shows the paired BT
|
||||
* devices.
|
||||
* @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;
|
||||
|
||||
import android.bluetooth.*;
|
||||
import java.util.Set;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.preference.ListPreference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class BluetoothDevicePreference extends ListPreference {
|
||||
|
||||
public BluetoothDevicePreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
BluetoothAdapter bta = BluetoothAdapter.getDefaultAdapter();
|
||||
if (bta == null)
|
||||
return; // BT not supported
|
||||
Set<BluetoothDevice> pairedDevices = bta.getBondedDevices();
|
||||
CharSequence[] entries = new CharSequence[pairedDevices.size()];
|
||||
CharSequence[] entryValues = new CharSequence[pairedDevices.size()];
|
||||
int i = 0;
|
||||
for (BluetoothDevice dev : pairedDevices) {
|
||||
entries[i] = dev.getName();
|
||||
entryValues[i] = dev.getAddress();
|
||||
i++;
|
||||
if (pairedDevices.size() == 0) {
|
||||
entries[0] = "No Devices";
|
||||
entryValues[0] = "";
|
||||
} else {
|
||||
int i = 0;
|
||||
for (BluetoothDevice dev : pairedDevices) {
|
||||
entries[i] = dev.getName();
|
||||
entryValues[i] = dev.getAddress();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
setEntries(entries);
|
||||
setEntryValues(entryValues);
|
||||
|
@ -1,3 +1,27 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file CompassView.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief A view of the compass heading.
|
||||
* @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;
|
||||
|
||||
import android.content.Context;
|
||||
@ -14,104 +38,104 @@ public class CompassView extends View {
|
||||
initCompassView();
|
||||
}
|
||||
|
||||
public CompassView(Context context, AttributeSet ats, int defaultStyle) {
|
||||
public CompassView(Context context, AttributeSet ats, int defaultStyle) {
|
||||
super(context, ats, defaultStyle);
|
||||
initCompassView();
|
||||
}
|
||||
|
||||
public CompassView(Context context, AttributeSet ats) {
|
||||
public CompassView(Context context, AttributeSet ats) {
|
||||
super(context, ats);
|
||||
initCompassView();
|
||||
}
|
||||
|
||||
protected void initCompassView() {
|
||||
protected void initCompassView() {
|
||||
setFocusable(true);
|
||||
|
||||
circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
circlePaint.setColor(R.color.background_color);
|
||||
circlePaint.setStrokeWidth(1);
|
||||
circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
circlePaint.setColor(getResources().getColor(R.color.background_color));
|
||||
circlePaint.setStrokeWidth(1);
|
||||
circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
Resources r = this.getResources();
|
||||
northString = r.getString(R.string.cardinal_north);
|
||||
eastString = r.getString(R.string.cardinal_east);
|
||||
southString = r.getString(R.string.cardinal_south);
|
||||
Resources r = this.getResources();
|
||||
northString = r.getString(R.string.cardinal_north);
|
||||
eastString = r.getString(R.string.cardinal_east);
|
||||
southString = r.getString(R.string.cardinal_south);
|
||||
westString = r.getString(R.string.cardinal_west);
|
||||
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
textPaint.setColor(r.getColor(R.color.text_color));
|
||||
textHeight = (int)textPaint.measureText("yY");
|
||||
markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
markerPaint.setColor(r.getColor(R.color.marker_color));
|
||||
markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
markerPaint.setColor(r.getColor(R.color.marker_color));
|
||||
}
|
||||
|
||||
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int measuredWidth = measure(widthMeasureSpec);
|
||||
int measuredWidth = measure(widthMeasureSpec);
|
||||
int measuredHeight = measure(heightMeasureSpec);
|
||||
int d = Math.min(measuredWidth, measuredHeight);
|
||||
int d = Math.min(measuredWidth, measuredHeight);
|
||||
setMeasuredDimension(d/2, d/2);
|
||||
}
|
||||
|
||||
private int measure(int measureSpec) {
|
||||
private int measure(int measureSpec) {
|
||||
int result = 0;
|
||||
// Decode the measurement specifications.
|
||||
// Decode the measurement specifications.
|
||||
|
||||
int specMode = MeasureSpec.getMode(measureSpec);
|
||||
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.
|
||||
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.
|
||||
} else {
|
||||
// As you want to fill the available space
|
||||
// always return the full available bounds.
|
||||
result = specSize;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private double bearing;
|
||||
public void setBearing(double bearing) {
|
||||
public void setBearing(double bearing) {
|
||||
this.bearing = bearing;
|
||||
}
|
||||
}
|
||||
|
||||
// Drawing related code
|
||||
private Paint markerPaint;
|
||||
private Paint textPaint;
|
||||
private Paint circlePaint;
|
||||
private String northString;
|
||||
private String eastString;
|
||||
private String southString;
|
||||
private String westString;
|
||||
private Paint markerPaint;
|
||||
private Paint textPaint;
|
||||
private Paint circlePaint;
|
||||
private String northString;
|
||||
private String eastString;
|
||||
private String southString;
|
||||
private String westString;
|
||||
private int textHeight;
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
int px = getMeasuredWidth() / 2;
|
||||
int px = getMeasuredWidth() / 2;
|
||||
int py = getMeasuredHeight() /2 ;
|
||||
int radius = Math.min(px, py);
|
||||
// Draw the background
|
||||
// Draw the background
|
||||
canvas.drawCircle(px, py, radius, circlePaint);
|
||||
|
||||
// Rotate our perspective so that the ÔtopÕ is
|
||||
// facing the current bearing.
|
||||
canvas.save();
|
||||
// Rotate our perspective so that the ÔtopÕ is
|
||||
// facing the current bearing.
|
||||
canvas.save();
|
||||
canvas.rotate((float) -bearing, px, py);
|
||||
|
||||
int textWidth = (int)textPaint.measureText("W");
|
||||
int cardinalX = px-textWidth/2;
|
||||
int textWidth = (int)textPaint.measureText("W");
|
||||
int cardinalX = px-textWidth/2;
|
||||
int cardinalY = py-radius+textHeight;
|
||||
|
||||
// Draw the marker every 15 degrees and text every 45.
|
||||
// Draw the marker every 15 degrees and text every 45.
|
||||
for (int i = 0; i < 24; i++) {
|
||||
// Draw a marker.
|
||||
// Draw a marker.
|
||||
canvas.drawLine(px, py-radius, px, py-radius+10, markerPaint);
|
||||
canvas.save();
|
||||
canvas.save();
|
||||
canvas.translate(0, textHeight);
|
||||
// Draw the cardinal points
|
||||
// Draw the cardinal points
|
||||
if (i % 6 == 0) {
|
||||
String dirString = null;
|
||||
switch (i) {
|
||||
case 0 : {
|
||||
dirString = northString;
|
||||
int arrowY = 2*textHeight;
|
||||
dirString = northString;
|
||||
int arrowY = 2*textHeight;
|
||||
canvas.drawLine(px, arrowY, px-5, 3*textHeight, markerPaint);
|
||||
canvas.drawLine(px, arrowY, px+5, 3*textHeight, markerPaint);
|
||||
break;
|
||||
@ -122,18 +146,18 @@ public class CompassView extends View {
|
||||
}
|
||||
canvas.drawText(dirString, cardinalX, cardinalY, textPaint);
|
||||
}
|
||||
else if (i % 3 == 0) {
|
||||
// Draw the text every alternate 45deg
|
||||
String angle = String.valueOf(i*15);
|
||||
else if (i % 3 == 0) {
|
||||
// Draw the text every alternate 45deg
|
||||
String angle = String.valueOf(i*15);
|
||||
float angleTextWidth = textPaint.measureText(angle);
|
||||
|
||||
int angleTextX = (int)(px-angleTextWidth/2);
|
||||
int angleTextY = py-radius+textHeight;
|
||||
int angleTextX = (int)(px-angleTextWidth/2);
|
||||
int angleTextY = py-radius+textHeight;
|
||||
canvas.drawText(angle, angleTextX, angleTextY, textPaint);
|
||||
}
|
||||
canvas.restore();
|
||||
canvas.rotate(15, px, py);
|
||||
}
|
||||
canvas.restore();
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,28 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file Controller.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Allows controlling the UAV over telemetry. This activity
|
||||
* pushes the appropriate settings to the remote device for it to
|
||||
* listen to the GCSReceiver.
|
||||
* @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;
|
||||
|
||||
import java.util.Observable;
|
||||
@ -9,16 +34,16 @@ import org.openpilot.uavtalk.UAVDataObject;
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
import org.openpilot.uavtalk.UAVObjectField;
|
||||
|
||||
import com.MobileAnarchy.Android.Widgets.Joystick.DualJoystickView;
|
||||
import com.MobileAnarchy.Android.Widgets.Joystick.JoystickMovedListener;
|
||||
import com.MobileAnarchy.Android.Widgets.Joystick.JoystickView;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.MobileAnarchy.Android.Widgets.Joystick.DualJoystickView;
|
||||
import com.MobileAnarchy.Android.Widgets.Joystick.JoystickMovedListener;
|
||||
import com.MobileAnarchy.Android.Widgets.Joystick.JoystickView;
|
||||
|
||||
public class Controller extends ObjectManagerActivity {
|
||||
private final String TAG = "Controller";
|
||||
|
||||
@ -29,18 +54,18 @@ public class Controller extends ObjectManagerActivity {
|
||||
private final int PITCH_CHANNEL = 2;
|
||||
private final int YAW_CHANNEL = 3;
|
||||
private final int FLIGHTMODE_CHANNEL = 4;
|
||||
|
||||
|
||||
private final int CHANNEL_MIN = 1000;
|
||||
private final int CHANNEL_MAX = 2000;
|
||||
private final int CHANNEL_NEUTRAL = 1500;
|
||||
private final int CHANNEL_NEUTRAL_THROTTLE = 1100;
|
||||
|
||||
|
||||
private double throttle = 0.1, roll = 0.1, pitch = -0.1, yaw = 0;
|
||||
private boolean updated;
|
||||
private boolean leftJoystickHeld, rightJoystickHeld;
|
||||
|
||||
|
||||
Timer sendTimer = new Timer();
|
||||
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@ -63,7 +88,7 @@ public class Controller extends ObjectManagerActivity {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
void onOPConnected() {
|
||||
super.onOPConnected();
|
||||
@ -74,43 +99,48 @@ public class Controller extends ObjectManagerActivity {
|
||||
manualControl.addUpdatedObserver(updatedObserver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
UAVDataObject manualControlSettings = (UAVDataObject) objMngr.getObject("ManualControlSettings");
|
||||
if(manualControlSettings != null) {
|
||||
Log.d(TAG, "Requested settings update");
|
||||
manualControlSettings.addUpdatedObserver(updatedObserver);
|
||||
manualControlSettings.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 = (double) tilt / MOVEMENT_RANGE;
|
||||
yaw = (double) pan / MOVEMENT_RANGE;
|
||||
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 = (double) (-tilt + (MOVEMENT_RANGE -5)) / (MOVEMENT_RANGE - 5);
|
||||
throttle = (-tilt + (MOVEMENT_RANGE -5)) / (MOVEMENT_RANGE - 5);
|
||||
throttle *= 0.5;
|
||||
if (throttle < 0)
|
||||
throttle = -1;
|
||||
roll = (double) pan / MOVEMENT_RANGE;
|
||||
roll = pan / MOVEMENT_RANGE;
|
||||
rightJoystickHeld = true;
|
||||
}
|
||||
@Override
|
||||
public void OnReleased() { rightJoystickHeld = false; throttle = -1; updated = true; }
|
||||
@Override
|
||||
public void OnReturnedToCenter() { }
|
||||
}) ;
|
||||
TimerTask controllerTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
uavobjHandler.post(new Runnable() {
|
||||
@Override
|
||||
@ -152,17 +182,19 @@ public class Controller extends ObjectManagerActivity {
|
||||
* The callbacks from the UAVOs must run in the correct thread to update the
|
||||
* UI. This is what using a runnable does.
|
||||
*/
|
||||
final Handler uavobjHandler = new Handler();
|
||||
final Handler uavobjHandler = new Handler();
|
||||
final Runnable updateText = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateManualControl();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private final Observer updatedObserver = new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
uavobjHandler.post(updateText);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -174,33 +206,33 @@ public class Controller extends ObjectManagerActivity {
|
||||
if (manualView != null && manualControl != null)
|
||||
manualView.setText(manualControl.toStringData());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Active GCS receiver mode
|
||||
*/
|
||||
private void activateGcsReceiver() {
|
||||
UAVObject manualControlSettings = objMngr.getObject("ManualControlSettings");
|
||||
|
||||
|
||||
if (manualControlSettings == null) {
|
||||
Toast.makeText(this, "Failed to get manual control settings", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
UAVObjectField channelGroups = manualControlSettings.getField("ChannelGroups");
|
||||
UAVObjectField channelNumber = manualControlSettings.getField("ChannelNumber");
|
||||
UAVObjectField channelMax = manualControlSettings.getField("ChannelMax");
|
||||
UAVObjectField channelNeutral = manualControlSettings.getField("ChannelNeutral");
|
||||
UAVObjectField channelMin = manualControlSettings.getField("ChannelMin");
|
||||
if (channelGroups == null || channelMax == null || channelNeutral == null ||
|
||||
if (channelGroups == null || channelMax == null || channelNeutral == null ||
|
||||
channelMin == null || channelNumber == null) {
|
||||
Toast.makeText(this, "Manual control settings not formatted correctly", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Configure the manual control module how the GCS controller expects
|
||||
* This order MUST correspond to the enumeration order of ChannelNumber in
|
||||
* This order MUST correspond to the enumeration order of ChannelNumber in
|
||||
* ManualControlSettings.
|
||||
*/
|
||||
*/
|
||||
int channels[] = { THROTTLE_CHANNEL, ROLL_CHANNEL, PITCH_CHANNEL, YAW_CHANNEL, FLIGHTMODE_CHANNEL };
|
||||
for (int i = 0; i < channels.length; i++) {
|
||||
channelGroups.setValue("GCS", channels[i]);
|
||||
@ -216,23 +248,23 @@ public class Controller extends ObjectManagerActivity {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Send settings to the UAV
|
||||
manualControlSettings.updated();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scale the channels to the output range the flight controller expects
|
||||
*/
|
||||
private float scaleChannel(double in, double neutral) {
|
||||
private float scaleChannel(double in, double neutral) {
|
||||
// Check bounds
|
||||
if (in > 1)
|
||||
if (in > 1)
|
||||
in = 1;
|
||||
if (in < -1)
|
||||
in = -1;
|
||||
|
||||
|
||||
if (in >= 0)
|
||||
return (float) (neutral + (CHANNEL_MAX - neutral) * in);
|
||||
return (float) (neutral + (neutral - CHANNEL_MIN) * in);
|
||||
|
@ -1,3 +1,26 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file HomePage.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Main launch page for the Android GCS actitivies
|
||||
* @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;
|
||||
|
||||
import android.content.Intent;
|
||||
@ -10,48 +33,54 @@ public class HomePage extends ObjectManagerActivity {
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.gcs_home);
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.gcs_home);
|
||||
|
||||
Button objectBrowser = (Button) findViewById(R.id.launch_object_browser);
|
||||
objectBrowser.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
startActivity(new Intent(HomePage.this, ObjectBrowser.class));
|
||||
}
|
||||
startActivity(new Intent(HomePage.this, ObjectBrowser.class));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Button pfd = (Button) findViewById(R.id.launch_pfd);
|
||||
pfd.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
startActivity(new Intent(HomePage.this, PFD.class));
|
||||
}
|
||||
startActivity(new Intent(HomePage.this, PfdActivity.class));
|
||||
}
|
||||
});
|
||||
|
||||
Button location = (Button) findViewById(R.id.launch_location);
|
||||
location.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
startActivity(new Intent(HomePage.this, UAVLocation.class));
|
||||
}
|
||||
startActivity(new Intent(HomePage.this, UAVLocation.class));
|
||||
}
|
||||
});
|
||||
|
||||
Button controller = (Button) findViewById(R.id.launch_controller);
|
||||
controller.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
startActivity(new Intent(HomePage.this, Controller.class));
|
||||
}
|
||||
startActivity(new Intent(HomePage.this, Controller.class));
|
||||
}
|
||||
});
|
||||
|
||||
Button logger = (Button) findViewById(R.id.launch_logger);
|
||||
logger.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
startActivity(new Intent(HomePage.this, Logger.class));
|
||||
startActivity(new Intent(HomePage.this, Logger.class));
|
||||
}
|
||||
});
|
||||
|
||||
Button alarms = (Button) findViewById(R.id.launch_alarms);
|
||||
alarms.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
startActivity(new Intent(HomePage.this, SystemAlarmActivity.class));
|
||||
startActivity(new Intent(HomePage.this, SystemAlarmActivity.class));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,3 +1,27 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file Logger.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Controller for logging data as well as interface for getting that
|
||||
* data on and off the tablet.
|
||||
* @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;
|
||||
|
||||
import java.io.File;
|
||||
@ -16,17 +40,17 @@ import android.widget.TextView;
|
||||
|
||||
|
||||
public class Logger extends ObjectManagerActivity {
|
||||
|
||||
|
||||
final String TAG = "Logger";
|
||||
|
||||
final boolean VERBOSE = false;
|
||||
final boolean DEBUG = true;
|
||||
|
||||
|
||||
private File file;
|
||||
private boolean logging;
|
||||
private FileOutputStream fileStream;
|
||||
private UAVTalk uavTalk;
|
||||
|
||||
|
||||
private int writtenBytes;
|
||||
private int writtenObjects;
|
||||
|
||||
@ -36,15 +60,15 @@ public class Logger extends ObjectManagerActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.logger);
|
||||
}
|
||||
|
||||
|
||||
private void onStartLogging() {
|
||||
|
||||
|
||||
File root = Environment.getExternalStorageDirectory();
|
||||
|
||||
|
||||
Date d = new Date();
|
||||
String date = (new SimpleDateFormat("yyyyMMdd_hhmmss")).format(d);
|
||||
String fileName = "/logs/logs_" + date + ".opl";
|
||||
|
||||
|
||||
file = new File(root, fileName);
|
||||
if (DEBUG) Log.d(TAG, "Trying for file: " + file.getAbsolutePath());
|
||||
try {
|
||||
@ -60,10 +84,10 @@ public class Logger extends ObjectManagerActivity {
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Could not write file " + e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
// TODO: if logging succeeded then retrieve all settings
|
||||
}
|
||||
|
||||
|
||||
private void onStopLogging() {
|
||||
if (DEBUG) Log.d(TAG, "Stop logging");
|
||||
logging = false;
|
||||
@ -74,11 +98,11 @@ public class Logger extends ObjectManagerActivity {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
void onOPConnected() {
|
||||
super.onOPConnected();
|
||||
|
||||
|
||||
if (DEBUG) Log.d(TAG, "onOPConnected()");
|
||||
onStartLogging();
|
||||
registerObjectUpdates(objMngr.getObjects());
|
||||
@ -104,7 +128,7 @@ public class Logger extends ObjectManagerActivity {
|
||||
onStartLogging();
|
||||
}
|
||||
/**
|
||||
* Called whenever any objects subscribed to via registerObjects
|
||||
* Called whenever any objects subscribed to via registerObjects
|
||||
*/
|
||||
@Override
|
||||
protected void objectUpdated(UAVObject obj) {
|
||||
@ -126,18 +150,18 @@ public class Logger extends ObjectManagerActivity {
|
||||
fileStream.write((byte)(size & 0x0000ff0000000000l) >> 40);
|
||||
fileStream.write((byte)(size & 0x00ff000000000000l) >> 48);
|
||||
fileStream.write((byte)(size & 0xff00000000000000l) >> 56);
|
||||
|
||||
|
||||
uavTalk.sendObject(obj, false, false);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
writtenBytes += obj.getNumBytes();
|
||||
writtenObjects ++;
|
||||
|
||||
((TextView) findViewById(R.id.logger_number_of_bytes)).setText(Integer.valueOf(writtenBytes).toString());
|
||||
((TextView) findViewById(R.id.logger_number_of_objects)).setText(Integer.valueOf(writtenObjects).toString());
|
||||
((TextView) findViewById(R.id.logger_number_of_objects)).setText(Integer.valueOf(writtenObjects).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,27 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file ObjectBrowser.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief A simple object browser for UAVOs that allows viewing, editing,
|
||||
* loading and saving.
|
||||
* @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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -6,6 +30,9 @@ import java.util.ListIterator;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import org.openpilot.uavtalk.UAVDataObject;
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
@ -16,6 +43,7 @@ import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
@ -23,10 +51,6 @@ import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
|
||||
import org.openpilot.uavtalk.UAVDataObject;
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
|
||||
public class ObjectBrowser extends ObjectManagerActivity implements OnSharedPreferenceChangeListener {
|
||||
|
||||
@ -36,24 +60,26 @@ public class ObjectBrowser extends ObjectManagerActivity implements OnSharedPref
|
||||
SharedPreferences prefs;
|
||||
ArrayAdapter<UAVDataObject> adapter;
|
||||
List<UAVDataObject> allObjects;
|
||||
|
||||
final Handler uavobjHandler = new Handler();
|
||||
|
||||
final Handler uavobjHandler = new Handler();
|
||||
final Runnable updateText = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateObject();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private final Observer updatedObserver = new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
uavobjHandler.post(updateText);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
setContentView(R.layout.object_browser);
|
||||
setContentView(R.layout.object_browser);
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -63,7 +89,7 @@ public class ObjectBrowser extends ObjectManagerActivity implements OnSharedPref
|
||||
void onOPConnected() {
|
||||
super.onOPConnected();
|
||||
Log.d(TAG, "onOPConnected()");
|
||||
|
||||
|
||||
OnCheckedChangeListener checkListener = new OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView,
|
||||
@ -71,10 +97,10 @@ public class ObjectBrowser extends ObjectManagerActivity implements OnSharedPref
|
||||
updateList();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
((CheckBox) findViewById(R.id.dataCheck)).setOnCheckedChangeListener(checkListener);
|
||||
((CheckBox) findViewById(R.id.settingsCheck)).setOnCheckedChangeListener(checkListener);
|
||||
|
||||
|
||||
((Button) findViewById(R.id.editButton)).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@ -87,7 +113,7 @@ public class ObjectBrowser extends ObjectManagerActivity implements OnSharedPref
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
((Button) findViewById(R.id.object_load_button)).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
@ -100,7 +126,7 @@ public class ObjectBrowser extends ObjectManagerActivity implements OnSharedPref
|
||||
objPer.getField("ObjectID").setValue(allObjects.get(selected_index).getObjID());
|
||||
objPer.getField("InstanceID").setValue(0);
|
||||
objPer.updated();
|
||||
|
||||
|
||||
allObjects.get(selected_index).updateRequested();
|
||||
}
|
||||
}
|
||||
@ -137,6 +163,7 @@ public class ObjectBrowser extends ObjectManagerActivity implements OnSharedPref
|
||||
objects.setAdapter(adapter);
|
||||
|
||||
objects.setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view,
|
||||
int position, long id) {
|
||||
|
||||
@ -149,9 +176,9 @@ public class ObjectBrowser extends ObjectManagerActivity implements OnSharedPref
|
||||
updateObject();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void updateObject() {
|
||||
//adapter.notifyDataSetChanged();
|
||||
TextView text = (TextView) findViewById(R.id.object_information);
|
||||
@ -161,6 +188,7 @@ public class ObjectBrowser extends ObjectManagerActivity implements OnSharedPref
|
||||
Log.d(TAG,"Update called but invalid index: " + selected_index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
||||
String key) {
|
||||
// TODO Auto-generated method stub
|
||||
|
@ -1,3 +1,26 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file ObjectEditor.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief A popup dialog for editing the contents of a UAVO.
|
||||
* @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;
|
||||
|
||||
import java.util.List;
|
||||
@ -17,7 +40,7 @@ import android.widget.Toast;
|
||||
|
||||
public class ObjectEditor extends ObjectManagerActivity {
|
||||
|
||||
static final String TAG = "ObjectEditor";
|
||||
static final String TAG = "ObjectEditor";
|
||||
String objectName;
|
||||
long objectID;
|
||||
long instID;
|
||||
@ -58,6 +81,7 @@ public class ObjectEditor extends ObjectManagerActivity {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOPConnected() {
|
||||
UAVObject obj = objMngr.getObject(objectID, instID);
|
||||
if (obj == null) {
|
||||
@ -86,15 +110,15 @@ public class ObjectEditor extends ObjectManagerActivity {
|
||||
Toast.makeText(this, "Save failed", Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
long thisId = objectID < 0 ? ((Long) 0x100000000l) + objectID : objectID;
|
||||
|
||||
long thisId = objectID < 0 ? 0x100000000l + objectID : objectID;
|
||||
objPer.getField("Operation").setValue("Save");
|
||||
objPer.getField("Selection").setValue("SingleObject");
|
||||
Log.d(TAG,"Saving with object id: " + objectID + " swapped to " + thisId);
|
||||
objPer.getField("ObjectID").setValue(thisId);
|
||||
objPer.getField("InstanceID").setValue(instID);
|
||||
objPer.updated();
|
||||
|
||||
|
||||
Toast.makeText(this, "Save succeeded", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@ -125,7 +149,7 @@ public class ObjectEditor extends ObjectManagerActivity {
|
||||
default:
|
||||
String val = ((EditText) editView.fields.get(field_idx)).getText().toString();
|
||||
Double num = Double.parseDouble(val);
|
||||
|
||||
|
||||
Log.e(TAG, "Updating field: " + field.getName() + " value: " + num);
|
||||
field.setValue(num, i);
|
||||
break;
|
||||
|
@ -1,3 +1,32 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file ObjectManagerActivity.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Base object for all activies that use the UAVObjectManager.
|
||||
* This class takes care of binding to the service and getting the
|
||||
* object manager as well as setting up callbacks to the objects of
|
||||
* interest that run on the UI thread.
|
||||
* Implements a new Android lifecycle: onOPConnected() / onOPDisconnected()
|
||||
* which indicates when a valid telemetry is established as well as a
|
||||
* valid object manager handle.
|
||||
* @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;
|
||||
|
||||
import java.util.List;
|
||||
@ -5,8 +34,10 @@ import java.util.ListIterator;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import org.openpilot.androidgcs.OPTelemetryService.LocalBinder;
|
||||
import org.openpilot.androidgcs.OPTelemetryService.TelemTask;
|
||||
import org.openpilot.androidgcs.fragments.ObjectManagerFragment;
|
||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService;
|
||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService.LocalBinder;
|
||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService.TelemTask;
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
|
||||
@ -32,7 +63,7 @@ public abstract class ObjectManagerActivity extends Activity {
|
||||
private static int LOGLEVEL = 0;
|
||||
// private static boolean WARN = LOGLEVEL > 1;
|
||||
private static boolean DEBUG = LOGLEVEL > 0;
|
||||
|
||||
|
||||
//! Object manager, populated by parent for the children to use
|
||||
UAVObjectManager objMngr;
|
||||
//! Indicates if the activity is bound to the service
|
||||
@ -45,16 +76,17 @@ public abstract class ObjectManagerActivity extends Activity {
|
||||
BroadcastReceiver connectedReceiver;
|
||||
//! Indicate if this activity has already connected it's telemetry callbacks
|
||||
private boolean telemetryStatsConnected = false;
|
||||
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
|
||||
connectedReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d(TAG, "Received intent");
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "Received intent");
|
||||
TelemTask task;
|
||||
if(intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_CONNECTED) == 0) {
|
||||
if(binder == null)
|
||||
@ -71,31 +103,32 @@ public abstract class ObjectManagerActivity extends Activity {
|
||||
onOPDisconnected();
|
||||
Log.d(TAG, "Disonnected()");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addCategory(OPTelemetryService.INTENT_CATEGORY_GCS);
|
||||
filter.addAction(OPTelemetryService.INTENT_ACTION_CONNECTED);
|
||||
filter.addAction(OPTelemetryService.INTENT_ACTION_DISCONNECTED);
|
||||
registerReceiver(connectedReceiver, filter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called whenever any objects subscribed to via registerObjects
|
||||
* Called whenever any objects subscribed to via registerObjects
|
||||
*/
|
||||
protected void objectUpdated(UAVObject obj) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A message handler and a custom Observer to use it which calls
|
||||
* objectUpdated with the right object type
|
||||
*/
|
||||
final Handler uavobjHandler = new Handler();
|
||||
private class UpdatedObserver implements Observer {
|
||||
final Handler uavobjHandler = new Handler();
|
||||
private class ActivityUpdatedObserver implements Observer {
|
||||
UAVObject obj;
|
||||
UpdatedObserver(UAVObject obj) { this.obj = obj; };
|
||||
ActivityUpdatedObserver(UAVObject obj) { this.obj = obj; };
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
uavobjHandler.post(new Runnable() {
|
||||
@Override
|
||||
@ -103,14 +136,35 @@ public abstract class ObjectManagerActivity extends Activity {
|
||||
});
|
||||
}
|
||||
};
|
||||
private class FragmentUpdatedObserver implements Observer {
|
||||
UAVObject obj;
|
||||
ObjectManagerFragment frag;
|
||||
FragmentUpdatedObserver(UAVObject obj, ObjectManagerFragment frag) {
|
||||
this.obj = obj;
|
||||
this.frag = frag;
|
||||
};
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
uavobjHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() { frag.objectUpdated(obj); }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Register an activity to receive updates from this object
|
||||
*
|
||||
*
|
||||
* the objectUpdated() method will be called in the original UI thread
|
||||
*/
|
||||
protected void registerObjectUpdates(UAVObject object) {
|
||||
object.addUpdatedObserver(new UpdatedObserver(object));
|
||||
object.addUpdatedObserver(new ActivityUpdatedObserver(object));
|
||||
}
|
||||
|
||||
public void registerObjectUpdates(UAVObject object,
|
||||
ObjectManagerFragment frag) {
|
||||
object.addUpdatedObserver(new FragmentUpdatedObserver(object, frag));
|
||||
}
|
||||
protected void registerObjectUpdates(List<List<UAVObject>> objects) {
|
||||
ListIterator<List<UAVObject>> li = objects.listIterator();
|
||||
@ -120,7 +174,7 @@ public abstract class ObjectManagerActivity extends Activity {
|
||||
registerObjectUpdates(li2.next());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updateStats() {
|
||||
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||
TextView rxRate = (TextView) findViewById(R.id.telemetry_stats_rx_rate);
|
||||
@ -131,8 +185,9 @@ public abstract class ObjectManagerActivity extends Activity {
|
||||
txRate.setText(Integer.valueOf((int) stats.getField("TxDataRate").getDouble()).toString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
final Observer telemetryObserver = new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
uavobjHandler.post(new Runnable() {
|
||||
@Override
|
||||
@ -142,31 +197,34 @@ public abstract class ObjectManagerActivity extends Activity {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Called when either the telemetry establishes a connection or
|
||||
* if it already has on creation of this activity
|
||||
*
|
||||
*
|
||||
* This should be called by all inherited classes if they want the telemetry bar etc
|
||||
*/
|
||||
void onOPConnected() {
|
||||
if ( telemetryStatsConnected )
|
||||
return;
|
||||
|
||||
|
||||
// We are not using the objectUpdated mechanism in place so that all the children
|
||||
// don't have to sort through the messages.
|
||||
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||
if (stats == null)
|
||||
return;
|
||||
|
||||
|
||||
stats.addUpdatedObserver(telemetryObserver);
|
||||
telemetryStatsConnected = true;
|
||||
updateStats();
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Notifying listeners about connection. There are " + connectionListeners.countObservers());
|
||||
connectionListeners.connected();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when telemetry drops the connection
|
||||
*
|
||||
*
|
||||
* This should be called by all inherited classes if they want the telemetry bar etc
|
||||
*/
|
||||
void onOPDisconnected() {
|
||||
@ -175,10 +233,17 @@ public abstract class ObjectManagerActivity extends Activity {
|
||||
TextView txRate = (TextView) findViewById(R.id.telemetry_stats_tx_rate);
|
||||
rxRate.setText("");
|
||||
txRate.setText("");
|
||||
|
||||
// Providing a null update triggers a disconnect on fragments
|
||||
connectionListeners.disconnected();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (!mBound || binder == null) {
|
||||
Log.e(TAG, "Unable to connect to service");
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
switch(item.getItemId()) {
|
||||
case R.id.menu_connect:
|
||||
binder.openConnection();
|
||||
@ -206,10 +271,13 @@ public abstract class ObjectManagerActivity extends Activity {
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
Intent intent = new Intent(this, OPTelemetryService.class);
|
||||
Intent intent = new Intent(getApplicationContext(),
|
||||
org.openpilot.androidgcs.telemetry.OPTelemetryService.class);
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "Attempting to bind: " + intent);
|
||||
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When stopping disconnect form the service and the broadcast receiver
|
||||
*/
|
||||
@ -221,17 +289,63 @@ public abstract class ObjectManagerActivity extends Activity {
|
||||
}
|
||||
|
||||
public void onBind() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks so ObjectManagerFragments get the onOPConnected and onOPDisconnected signals
|
||||
*/
|
||||
class ConnectionObserver extends Observable {
|
||||
public void disconnected() {
|
||||
synchronized(this) {
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
}
|
||||
public void connected() {
|
||||
synchronized(this) {
|
||||
setChanged();
|
||||
notifyObservers(objMngr);
|
||||
}
|
||||
}
|
||||
};
|
||||
private final ConnectionObserver connectionListeners = new ConnectionObserver();
|
||||
public class OnConnectionListener implements Observer {
|
||||
|
||||
// Local reference of the fragment to notify, store in constructor
|
||||
ObjectManagerFragment fragment;
|
||||
OnConnectionListener(ObjectManagerFragment fragment) { this.fragment = fragment; };
|
||||
|
||||
// Whenever the observer is updated either conenct or disconnect based on the data
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
Log.d(TAG, "onConnectionListener called");
|
||||
if (data == null)
|
||||
fragment.onOPDisconnected();
|
||||
else
|
||||
fragment.onOPConnected(objMngr);
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
public void addOnConnectionListenerFragment(ObjectManagerFragment frag) {
|
||||
connectionListeners.addObserver(new OnConnectionListener(frag));
|
||||
if (DEBUG) Log.d(TAG, "Connecting " + frag + " there are now " + connectionListeners.countObservers());
|
||||
if (mConnected)
|
||||
frag.onOPConnected(objMngr);
|
||||
}
|
||||
|
||||
|
||||
/** Defines callbacks for service binding, passed to bindService() */
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName arg0, IBinder service) {
|
||||
// We've bound to LocalService, cast the IBinder and attempt to open a connection
|
||||
// We've bound to LocalService, cast the IBinder and attempt to open a connection
|
||||
if (DEBUG) Log.d(TAG,"Service bound");
|
||||
mBound = true;
|
||||
binder = (LocalBinder) service;
|
||||
|
||||
|
||||
if(binder.isConnected()) {
|
||||
TelemTask task;
|
||||
if((task = binder.getTelemTask(0)) != null) {
|
||||
@ -239,10 +353,11 @@ public abstract class ObjectManagerActivity extends Activity {
|
||||
mConnected = true;
|
||||
onOPConnected();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
mBound = false;
|
||||
binder = null;
|
||||
|
@ -1,56 +0,0 @@
|
||||
package org.openpilot.androidgcs;
|
||||
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class PFD extends ObjectManagerActivity {
|
||||
|
||||
final long MIN_UPDATE_PERIOD = 50;
|
||||
long lastUpdateMs;
|
||||
double heading;
|
||||
double roll;
|
||||
double pitch;
|
||||
|
||||
/**
|
||||
* Update the UI whenever the attitude is updated
|
||||
*/
|
||||
protected void objectUpdated(UAVObject obj) {
|
||||
// Throttle the UI redraws. Eventually this should maybe come from a periodic task
|
||||
if ((System.currentTimeMillis() - lastUpdateMs) < MIN_UPDATE_PERIOD)
|
||||
return;
|
||||
if (obj.getName().compareTo("AttitudeActual") != 0)
|
||||
return;
|
||||
|
||||
lastUpdateMs = System.currentTimeMillis();
|
||||
|
||||
heading = obj.getField("Yaw").getDouble();
|
||||
pitch = obj.getField("Pitch").getDouble();
|
||||
roll = obj.getField("Roll").getDouble();
|
||||
|
||||
CompassView compass = (CompassView) findViewById(R.id.compass_view);
|
||||
compass.setBearing((int) heading);
|
||||
compass.invalidate();
|
||||
|
||||
AttitudeView attitude = (AttitudeView) findViewById(R.id.attitude_view);
|
||||
attitude.setRoll(roll / 180 * Math.PI);
|
||||
attitude.setPitch(pitch / 180 * Math.PI);
|
||||
attitude.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.pfd);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onOPConnected() {
|
||||
super.onOPConnected();
|
||||
|
||||
// Connect the update method to AttitudeActual
|
||||
UAVObject obj = objMngr.getObject("AttitudeActual");
|
||||
if (obj != null)
|
||||
registerObjectUpdates(obj);
|
||||
}
|
||||
}
|
58
androidgcs/src/org/openpilot/androidgcs/PfdActivity.java
Normal file
58
androidgcs/src/org/openpilot/androidgcs/PfdActivity.java
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file PfdActivity.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Shows the PFD activity.
|
||||
* @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;
|
||||
|
||||
import org.openpilot.androidgcs.fragments.PFD;
|
||||
|
||||
import android.app.FragmentTransaction;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public class PfdActivity extends ObjectManagerActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(createUI());
|
||||
}
|
||||
|
||||
private View createUI() {
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
|
||||
layout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
layout.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
AbsListView.LayoutParams.MATCH_PARENT,
|
||||
AbsListView.LayoutParams.MATCH_PARENT));
|
||||
layout.setId(0x101);
|
||||
{
|
||||
FragmentTransaction fragmentTransaction = getFragmentManager()
|
||||
.beginTransaction();
|
||||
fragmentTransaction.add(0x101, new PFD());
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
}
|
@ -1,3 +1,27 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file Preferences.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Displays the preferences dialog.
|
||||
* @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;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
@ -1,51 +1,37 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file SystemAlarmActivity.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief An activity that displays the SystemAlarmsFragment.
|
||||
* @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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
import org.openpilot.uavtalk.UAVObjectField;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* All the work for this activity is performed by it's fragment
|
||||
*/
|
||||
public class SystemAlarmActivity extends ObjectManagerActivity {
|
||||
/**
|
||||
* Update the UI whenever the attitude is updated
|
||||
*/
|
||||
protected void objectUpdated(UAVObject obj) {
|
||||
if (obj.getName().compareTo("SystemAlarms") != 0)
|
||||
return;
|
||||
|
||||
TextView alarms = (TextView) findViewById(R.id.system_alarms_status);
|
||||
UAVObjectField a = obj.getField("Alarm");
|
||||
List<String> names = a.getElementNames();
|
||||
String contents = new String();
|
||||
List <String> options = a.getOptions();
|
||||
|
||||
// Rank the alarms by order of severity, skip uninitialized
|
||||
for (int j = options.size() - 1; j > 0; j--) {
|
||||
for (int i = 0; i < names.size(); i++) {
|
||||
if(a.getDouble(i) == j)
|
||||
contents += names.get(i) + " : " + a.getValue(i).toString() + "\n";
|
||||
}
|
||||
}
|
||||
alarms.setText(contents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.system_alarms);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onOPConnected() {
|
||||
super.onOPConnected();
|
||||
|
||||
// Connect the update method to AttitudeActual
|
||||
UAVObject obj = objMngr.getObject("SystemAlarms");
|
||||
if (obj != null)
|
||||
registerObjectUpdates(obj);
|
||||
objectUpdated(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,29 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file TelemetryWidget.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief A widget that shows the status of telemetry.
|
||||
* @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;
|
||||
|
||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.ComponentName;
|
||||
@ -8,7 +32,7 @@ import android.content.Intent;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
public class TelemetryWidget extends AppWidgetProvider {
|
||||
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if(intent.getAction().equals(OPTelemetryService.INTENT_ACTION_CONNECTED)) {
|
||||
@ -16,11 +40,11 @@ public class TelemetryWidget extends AppWidgetProvider {
|
||||
}
|
||||
if(intent.getAction().equals(OPTelemetryService.INTENT_ACTION_DISCONNECTED)) {
|
||||
changeStatus(context, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
super.onReceive(context, intent);
|
||||
}
|
||||
|
||||
|
||||
public void changeStatus(Context context, boolean status) {
|
||||
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.telemetry_widget);
|
||||
updateViews.setTextViewText(R.id.telemetryWidgetStatus, "Connection status: " + status);
|
||||
@ -30,6 +54,7 @@ public class TelemetryWidget extends AppWidgetProvider {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
final int N = appWidgetIds.length;
|
||||
|
||||
@ -44,6 +69,6 @@ public class TelemetryWidget extends AppWidgetProvider {
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,23 +1,39 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file UAVLocation.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Display the UAV location on google maps
|
||||
* @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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import org.openpilot.androidgcs.OPTelemetryService.LocalBinder;
|
||||
import org.openpilot.androidgcs.OPTelemetryService.TelemTask;
|
||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService;
|
||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService.LocalBinder;
|
||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService.TelemTask;
|
||||
import org.openpilot.uavtalk.UAVDataObject;
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
|
||||
import com.google.android.maps.GeoPoint;
|
||||
import com.google.android.maps.MapActivity;
|
||||
import com.google.android.maps.MapController;
|
||||
import com.google.android.maps.MapView;
|
||||
import com.google.android.maps.Overlay;
|
||||
import com.google.android.maps.Projection;
|
||||
import com.google.android.maps.MyLocationOverlay;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@ -36,47 +52,55 @@ import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
||||
public class UAVLocation extends MapActivity
|
||||
{
|
||||
import com.google.android.maps.GeoPoint;
|
||||
import com.google.android.maps.MapActivity;
|
||||
import com.google.android.maps.MapController;
|
||||
import com.google.android.maps.MapView;
|
||||
import com.google.android.maps.MyLocationOverlay;
|
||||
import com.google.android.maps.Overlay;
|
||||
import com.google.android.maps.Projection;
|
||||
|
||||
public class UAVLocation extends MapActivity
|
||||
{
|
||||
private final String TAG = "UAVLocation";
|
||||
private static int LOGLEVEL = 0;
|
||||
// private static boolean WARN = LOGLEVEL > 1;
|
||||
private static boolean DEBUG = LOGLEVEL > 0;
|
||||
|
||||
private MapView mapView;
|
||||
private MapView mapView;
|
||||
private MapController mapController;
|
||||
|
||||
UAVObjectManager objMngr;
|
||||
boolean mBound = false;
|
||||
boolean mConnected = false;
|
||||
LocalBinder binder;
|
||||
org.openpilot.androidgcs.telemetry.OPTelemetryService.LocalBinder binder;
|
||||
|
||||
GeoPoint homeLocation;
|
||||
GeoPoint uavLocation;
|
||||
|
||||
@Override public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
setContentView(R.layout.map_layout);
|
||||
super.onCreate(icicle);
|
||||
setContentView(R.layout.map_layout);
|
||||
mapView = (MapView)findViewById(R.id.map_view);
|
||||
mapController = mapView.getController();
|
||||
|
||||
mapView.displayZoomControls(true);
|
||||
Double lat = 37.422006*1E6;
|
||||
Double lng = -122.084095*1E6;
|
||||
Double lat = 37.422006*1E6;
|
||||
Double lng = -122.084095*1E6;
|
||||
homeLocation = new GeoPoint(lat.intValue(), lng.intValue());
|
||||
uavLocation = homeLocation;
|
||||
mapController.setCenter(homeLocation);
|
||||
mapController.setCenter(homeLocation);
|
||||
mapController.setZoom(18);
|
||||
|
||||
|
||||
List<Overlay> overlays = mapView.getOverlays();
|
||||
UAVOverlay myOverlay = new UAVOverlay();
|
||||
overlays.add(myOverlay);
|
||||
|
||||
UAVOverlay myOverlay = new UAVOverlay();
|
||||
overlays.add(myOverlay);
|
||||
|
||||
MyLocationOverlay myLocationOverlay = new MyLocationOverlay(this, mapView);
|
||||
myLocationOverlay.enableMyLocation();
|
||||
myLocationOverlay.enableCompass();
|
||||
overlays.add(myLocationOverlay);
|
||||
|
||||
|
||||
mapView.postInvalidate();
|
||||
|
||||
// ObjectManager related stuff (can't inherit standard class)
|
||||
@ -86,7 +110,7 @@ public class UAVLocation extends MapActivity
|
||||
Log.d(TAG, "Received intent");
|
||||
TelemTask task;
|
||||
if(intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_CONNECTED) == 0) {
|
||||
|
||||
|
||||
if(binder == null)
|
||||
return;
|
||||
if((task = binder.getTelemTask(0)) == null)
|
||||
@ -101,9 +125,9 @@ public class UAVLocation extends MapActivity
|
||||
onOPDisconnected();
|
||||
Log.d(TAG, "Disonnected()");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addCategory(OPTelemetryService.INTENT_CATEGORY_GCS);
|
||||
filter.addAction(OPTelemetryService.INTENT_ACTION_CONNECTED);
|
||||
@ -111,103 +135,108 @@ public class UAVLocation extends MapActivity
|
||||
registerReceiver(connectedReceiver, filter);
|
||||
}
|
||||
|
||||
//@Override
|
||||
//@Override
|
||||
@Override
|
||||
protected boolean isRouteDisplayed() {
|
||||
// IMPORTANT: This method must return true if your Activity // is displaying driving directions. Otherwise return false.
|
||||
// IMPORTANT: This method must return true if your Activity // is displaying driving directions. Otherwise return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
public class UAVOverlay extends Overlay {
|
||||
Bitmap homeSymbol = BitmapFactory.decodeResource(getResources(), R.drawable.ic_home);
|
||||
Bitmap uavSymbol = BitmapFactory.decodeResource(getResources(), R.drawable.ic_uav);
|
||||
@Override
|
||||
@Override
|
||||
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
|
||||
|
||||
|
||||
Projection projection = mapView.getProjection();
|
||||
|
||||
|
||||
if (shadow == false) {
|
||||
|
||||
Point myPoint = new Point();
|
||||
Point myPoint = new Point();
|
||||
projection.toPixels(uavLocation, myPoint);
|
||||
|
||||
|
||||
//// Draw UAV
|
||||
// Create and setup your paint brush
|
||||
Paint paint = new Paint();
|
||||
paint.setARGB(250, 255, 0, 0);
|
||||
paint.setAntiAlias(true);
|
||||
// Create and setup your paint brush
|
||||
Paint paint = new Paint();
|
||||
paint.setARGB(250, 255, 0, 0);
|
||||
paint.setAntiAlias(true);
|
||||
paint.setFakeBoldText(true);
|
||||
|
||||
// Draw on the canvas
|
||||
canvas.drawBitmap(uavSymbol, myPoint.x - uavSymbol.getWidth() / 2,
|
||||
|
||||
// Draw on the canvas
|
||||
canvas.drawBitmap(uavSymbol, myPoint.x - uavSymbol.getWidth() / 2,
|
||||
myPoint.y - uavSymbol.getHeight() / 2, paint);
|
||||
canvas.drawText("UAV", myPoint.x+uavSymbol.getWidth() / 2, myPoint.y, paint);
|
||||
|
||||
canvas.drawText("UAV", myPoint.x+uavSymbol.getWidth() / 2, myPoint.y, paint);
|
||||
|
||||
//// Draw Home
|
||||
myPoint = new Point();
|
||||
projection.toPixels(homeLocation, myPoint);
|
||||
|
||||
// Create and setup your paint brush
|
||||
paint.setARGB(250, 0, 0, 0);
|
||||
paint.setAntiAlias(true);
|
||||
// Create and setup your paint brush
|
||||
paint.setARGB(250, 0, 0, 0);
|
||||
paint.setAntiAlias(true);
|
||||
paint.setFakeBoldText(true);
|
||||
|
||||
canvas.drawBitmap(homeSymbol, myPoint.x - homeSymbol.getWidth() / 2,
|
||||
myPoint.y - homeSymbol.getHeight() / 2, paint);
|
||||
canvas.drawText("Home", myPoint.x+homeSymbol.getWidth(), myPoint.y, paint);
|
||||
|
||||
}
|
||||
canvas.drawBitmap(homeSymbol, myPoint.x - homeSymbol.getWidth() / 2,
|
||||
myPoint.y - homeSymbol.getHeight() / 2, paint);
|
||||
canvas.drawText("Home", myPoint.x+homeSymbol.getWidth(), myPoint.y, paint);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTap(GeoPoint point, MapView mapView1) {
|
||||
// Return true if screen tap is handled by this overlay
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void onOPConnected() {
|
||||
UAVObject obj = objMngr.getObject("HomeLocation");
|
||||
if(obj != null)
|
||||
obj.addUpdatedObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
UAVDataObject obj = (UAVDataObject) data;
|
||||
Double lat = obj.getField("Latitude").getDouble() / 10;
|
||||
Double lon = obj.getField("Longitude").getDouble() / 10;
|
||||
homeLocation = new GeoPoint(lat.intValue(), lon.intValue());
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mapController.setCenter(homeLocation);
|
||||
}
|
||||
mapController.setCenter(homeLocation);
|
||||
}
|
||||
});
|
||||
System.out.println("HomeLocation: " + homeLocation.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
obj.updateRequested();
|
||||
|
||||
|
||||
obj = objMngr.getObject("PositionActual");
|
||||
if(obj != null)
|
||||
obj.addUpdatedObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
uavLocation = getUavLocation();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mapView.invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private GeoPoint getUavLocation() {
|
||||
UAVObject pos = (UAVObject) objMngr.getObject("PositionActual");
|
||||
UAVObject pos = objMngr.getObject("PositionActual");
|
||||
if (pos == null)
|
||||
return new GeoPoint(0,0);
|
||||
|
||||
UAVObject home = (UAVObject) objMngr.getObject("HomeLocation");
|
||||
if (home == null)
|
||||
|
||||
UAVObject home = objMngr.getObject("HomeLocation");
|
||||
if (home == null)
|
||||
return new GeoPoint(0,0);
|
||||
|
||||
|
||||
double lat, lon, alt;
|
||||
lat = home.getField("Latitude").getDouble() / 10.0e6;
|
||||
lon = home.getField("Longitude").getDouble() / 10.0e6;
|
||||
@ -217,23 +246,23 @@ public class UAVLocation extends MapActivity
|
||||
double T0, T1;
|
||||
T0 = alt+6.378137E6;
|
||||
T1 = Math.cos(lat * Math.PI / 180.0)*(alt+6.378137E6);
|
||||
|
||||
|
||||
// Get the NED coordinates
|
||||
double NED0, NED1;
|
||||
NED0 = pos.getField("North").getDouble();
|
||||
NED1 = pos.getField("East").getDouble();
|
||||
|
||||
|
||||
// Compute the LLA coordinates
|
||||
lat = lat + (NED0 / T0) * 180.0 / Math.PI;
|
||||
lon = lon + (NED1 / T1) * 180.0 / Math.PI;
|
||||
|
||||
return new GeoPoint((int) (lat * 1e6), (int) (lon * 1e6));
|
||||
}
|
||||
|
||||
|
||||
void onOPDisconnected() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch(item.getItemId()) {
|
||||
@ -265,15 +294,16 @@ public class UAVLocation extends MapActivity
|
||||
Intent intent = new Intent(this, OPTelemetryService.class);
|
||||
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
|
||||
public void onBind() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
/** Defines callbacks for service binding, passed to bindService() */
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName arg0, IBinder service) {
|
||||
// We've bound to LocalService, cast the IBinder and attempt to open a connection
|
||||
// We've bound to LocalService, cast the IBinder and attempt to open a connection
|
||||
if (DEBUG) Log.d(TAG,"Service bound");
|
||||
mBound = true;
|
||||
binder = (LocalBinder) service;
|
||||
@ -285,10 +315,11 @@ public class UAVLocation extends MapActivity
|
||||
mConnected = true;
|
||||
onOPConnected();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
mBound = false;
|
||||
binder = null;
|
||||
|
@ -0,0 +1,104 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file ObjectManagerFragment.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Base class for all fragments that use the UAVObjectManager. This
|
||||
* supports all the extensions the ObjectManagerActivity does, namely
|
||||
* access to the UAVObjectManager and callbacks in the UI thread for
|
||||
* object updates.
|
||||
* @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.fragments;
|
||||
|
||||
import org.openpilot.androidgcs.ObjectManagerActivity;
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
public class ObjectManagerFragment extends Fragment {
|
||||
|
||||
private static final String TAG = ObjectManagerFragment.class.getSimpleName();
|
||||
private static final int LOGLEVEL = 0;
|
||||
// private static boolean WARN = LOGLEVEL > 1;
|
||||
private static final boolean DEBUG = LOGLEVEL > 0;
|
||||
|
||||
UAVObjectManager objMngr;
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (DEBUG) Log.d(TAG, "Created an ObjectManagerFragment");
|
||||
// For an activity this registers against the telemetry service intents. Fragments must be notified by their
|
||||
// parent activity
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach to the parent activity so it can notify us when the connection
|
||||
* changed
|
||||
*/
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
if (DEBUG) Log.d(TAG,"onAttach");
|
||||
|
||||
ObjectManagerActivity castActivity = null;
|
||||
try {
|
||||
castActivity = (ObjectManagerActivity)activity;
|
||||
} catch (ClassCastException e) {
|
||||
throw new android.app.Fragment.InstantiationException(
|
||||
"Attaching a ObjectManagerFragment to an activity failed because the parent activity is not a ObjectManagerActivity",
|
||||
e);
|
||||
}
|
||||
castActivity.addOnConnectionListenerFragment(this);
|
||||
}
|
||||
|
||||
|
||||
// The below methods should all be called by the parent activity at the appropriate times
|
||||
public void onOPConnected(UAVObjectManager objMngr) {
|
||||
this.objMngr = objMngr;
|
||||
if (DEBUG) Log.d(TAG,"onOPConnected");
|
||||
}
|
||||
|
||||
public void onOPDisconnected() {
|
||||
objMngr = null;
|
||||
if (DEBUG) Log.d(TAG,"onOPDisconnected");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever any objects subscribed to via registerObjects
|
||||
*/
|
||||
public void objectUpdated(UAVObject obj) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Register on the activities object monitor handler so that updates
|
||||
* occur within that UI thread. No need to maintain a handler for
|
||||
* each fragment.
|
||||
*/
|
||||
protected void registerObjectUpdates(UAVObject object) {
|
||||
((ObjectManagerActivity) getActivity()).registerObjectUpdates(object, this);
|
||||
}
|
||||
|
||||
}
|
93
androidgcs/src/org/openpilot/androidgcs/fragments/PFD.java
Normal file
93
androidgcs/src/org/openpilot/androidgcs/fragments/PFD.java
Normal file
@ -0,0 +1,93 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file PFD.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief The PFD display fragment
|
||||
* @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.fragments;
|
||||
|
||||
import org.openpilot.androidgcs.AttitudeView;
|
||||
import org.openpilot.androidgcs.R;
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class PFD extends ObjectManagerFragment {
|
||||
|
||||
private static final String TAG = ObjectManagerFragment.class
|
||||
.getSimpleName();
|
||||
private static final int LOGLEVEL = 0;
|
||||
// private static boolean WARN = LOGLEVEL > 1;
|
||||
private static final boolean DEBUG = LOGLEVEL > 0;
|
||||
|
||||
// @Override
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.pfd, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOPConnected(UAVObjectManager objMngr) {
|
||||
super.onOPConnected(objMngr);
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "On connected");
|
||||
|
||||
UAVObject obj = objMngr.getObject("AttitudeActual");
|
||||
if (obj != null)
|
||||
registerObjectUpdates(obj);
|
||||
objectUpdated(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever any objects subscribed to via registerObjects
|
||||
*/
|
||||
@Override
|
||||
public void objectUpdated(UAVObject obj) {
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "Updated");
|
||||
|
||||
double pitch = obj.getField("Pitch").getDouble();
|
||||
double roll = obj.getField("Roll").getDouble();
|
||||
|
||||
// TODO: These checks, while sensible, are necessary because the
|
||||
// callbacks aren't
|
||||
// removed when we switch to different activities sharing this fragment
|
||||
Activity parent = getActivity();
|
||||
AttitudeView attitude = null;
|
||||
if (parent != null)
|
||||
attitude = (AttitudeView) parent.findViewById(R.id.attitude_view);
|
||||
if (attitude != null) {
|
||||
attitude.setRoll(roll);
|
||||
attitude.setPitch(pitch);
|
||||
attitude.invalidate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file SystemAlarmsFragment.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief A fragment that will connect to the SystemAlarms and visualize them.
|
||||
* @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.fragments;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.openpilot.androidgcs.R;
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
import org.openpilot.uavtalk.UAVObjectField;
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class SystemAlarmsFragment extends ObjectManagerFragment {
|
||||
|
||||
private static final String TAG = SystemAlarmsFragment.class.getSimpleName();
|
||||
private static final int LOGLEVEL = 0;
|
||||
// private static boolean WARN = LOGLEVEL > 1;
|
||||
private static final boolean DEBUG = LOGLEVEL > 0;
|
||||
|
||||
//@Override
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.system_alarms_fragment, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOPConnected(UAVObjectManager objMngr) {
|
||||
super.onOPConnected(objMngr);
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "On connected");
|
||||
|
||||
UAVObject obj = objMngr.getObject("SystemAlarms");
|
||||
if (obj != null)
|
||||
registerObjectUpdates(obj);
|
||||
objectUpdated(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever any objects subscribed to via registerObjects
|
||||
*/
|
||||
@Override
|
||||
public void objectUpdated(UAVObject obj) {
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "Updated");
|
||||
if (obj.getName().compareTo("SystemAlarms") == 0) {
|
||||
TextView alarms = (TextView) getActivity().findViewById(R.id.system_alarms_fragment_field);
|
||||
UAVObjectField a = obj.getField("Alarm");
|
||||
List<String> names = a.getElementNames();
|
||||
String contents = new String();
|
||||
List <String> options = a.getOptions();
|
||||
|
||||
// Rank the alarms by order of severity, skip uninitialized
|
||||
for (int j = options.size() - 1; j > 0; j--) {
|
||||
for (int i = 0; i < names.size(); i++) {
|
||||
if(a.getDouble(i) == j)
|
||||
contents += names.get(i) + " : " + a.getValue(i).toString() + "\n";
|
||||
}
|
||||
}
|
||||
alarms.setText(contents);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file BluetoothUAVTalk.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Telemetry over bluetooth.
|
||||
* @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.telemetry;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
import org.openpilot.uavtalk.UAVTalk;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
@TargetApi(10) public class BluetoothUAVTalk {
|
||||
private final String TAG = "BluetoothUAVTalk";
|
||||
public static int LOGLEVEL = 2;
|
||||
public static boolean WARN = LOGLEVEL > 1;
|
||||
public static boolean DEBUG = LOGLEVEL > 0;
|
||||
|
||||
// Temporarily define fixed device name
|
||||
private String device_name = "RN42-222D";
|
||||
private final static UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
|
||||
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
private BluetoothSocket socket;
|
||||
private BluetoothDevice device;
|
||||
private UAVTalk uavTalk;
|
||||
private boolean connected;
|
||||
|
||||
public BluetoothUAVTalk(Context caller) {
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(caller);
|
||||
device_name = prefs.getString("bluetooth_mac","");
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Trying to open UAVTalk with " + device_name);
|
||||
|
||||
connected = false;
|
||||
device = null;
|
||||
|
||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (mBluetoothAdapter == null) {
|
||||
// Device does not support Bluetooth
|
||||
Log.e(TAG, "Device does not support Bluetooth");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mBluetoothAdapter.isEnabled()) {
|
||||
// Enable bluetooth if it isn't already
|
||||
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
||||
caller.sendOrderedBroadcast(enableBtIntent, "android.permission.BLUETOOTH_ADMIN", new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.e(TAG,"Received " + context + intent);
|
||||
//TODO: some logic here to see if it worked
|
||||
queryDevices();
|
||||
}
|
||||
}, null, Activity.RESULT_OK, null, null);
|
||||
} else {
|
||||
queryDevices();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean connect(UAVObjectManager objMngr) {
|
||||
if( getConnected() )
|
||||
return true;
|
||||
if( !getFoundDevice() )
|
||||
return false;
|
||||
if( !openTelemetryBluetooth(objMngr) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean getConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
public boolean getFoundDevice() {
|
||||
return (device != null);
|
||||
}
|
||||
|
||||
public UAVTalk getUavtalk() {
|
||||
return uavTalk;
|
||||
}
|
||||
|
||||
private void queryDevices() {
|
||||
Log.d(TAG, "Searching for devices");
|
||||
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
|
||||
// If there are paired devices
|
||||
if (pairedDevices.size() > 0) {
|
||||
// Loop through paired devices
|
||||
for (BluetoothDevice device : pairedDevices) {
|
||||
// Add the name and address to an array adapter to show in a ListView
|
||||
//mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
|
||||
Log.d(TAG, "Paired device: " + device.getAddress() + " compared to " + device_name);
|
||||
if(device.getAddress().compareTo(device_name) == 0) {
|
||||
Log.d(TAG, "Found device: " + device.getName());
|
||||
this.device = device;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean openTelemetryBluetooth(UAVObjectManager objMngr) {
|
||||
Log.d(TAG, "Opening connection to " + device.getName());
|
||||
socket = null;
|
||||
connected = false;
|
||||
try {
|
||||
socket = device.createInsecureRfcommSocketToServiceRecord(MY_UUID);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG,"Unable to create Rfcomm socket");
|
||||
return false;
|
||||
//e.printStackTrace();
|
||||
}
|
||||
|
||||
mBluetoothAdapter.cancelDiscovery();
|
||||
|
||||
try {
|
||||
socket.connect();
|
||||
}
|
||||
catch (IOException e) {
|
||||
Log.e(TAG,"Unable to connect to requested device", e);
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e2) {
|
||||
Log.e(TAG, "unable to close() socket during connection failure", e2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
connected = true;
|
||||
|
||||
try {
|
||||
uavTalk = new UAVTalk(socket.getInputStream(), socket.getOutputStream(), objMngr);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG,"Error starting UAVTalk");
|
||||
// TODO Auto-generated catch block
|
||||
//e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,479 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file OPTelemetryService.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Provides UAVTalk telemetry over multiple physical links. The
|
||||
* details of each of these are in their respective connection
|
||||
* classes. This mostly creates those threads based on the selected
|
||||
* preferences.
|
||||
* @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.telemetry;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import org.openpilot.uavtalk.Telemetry;
|
||||
import org.openpilot.uavtalk.TelemetryMonitor;
|
||||
import org.openpilot.uavtalk.UAVDataObject;
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
import org.openpilot.uavtalk.UAVTalk;
|
||||
import org.openpilot.uavtalk.uavobjects.UAVObjectsInitialize;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class OPTelemetryService extends Service {
|
||||
|
||||
// Logging settings
|
||||
private final String TAG = OPTelemetryService.class.getSimpleName();
|
||||
public static int LOGLEVEL = 0;
|
||||
public static boolean WARN = LOGLEVEL > 1;
|
||||
public static boolean DEBUG = LOGLEVEL > 0;
|
||||
|
||||
// Intent category
|
||||
public final static String INTENT_CATEGORY_GCS = "org.openpilot.intent.category.GCS";
|
||||
|
||||
// Intent actions
|
||||
public final static String INTENT_ACTION_CONNECTED = "org.openpilot.intent.action.CONNECTED";
|
||||
public final static String INTENT_ACTION_DISCONNECTED = "org.openpilot.intent.action.DISCONNECTED";
|
||||
|
||||
// Variables for local message handler thread
|
||||
private Looper mServiceLooper;
|
||||
private ServiceHandler mServiceHandler;
|
||||
private static HandlerThread thread;
|
||||
|
||||
// Message ids
|
||||
static final int MSG_START = 0;
|
||||
static final int MSG_CONNECT = 1;
|
||||
static final int MSG_DISCONNECT = 3;
|
||||
static final int MSG_TOAST = 100;
|
||||
|
||||
private boolean terminate = false;
|
||||
|
||||
private Thread activeTelem;
|
||||
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
|
||||
private final class ServiceHandler extends Handler {
|
||||
public ServiceHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "handleMessage: " + msg);
|
||||
switch(msg.arg1) {
|
||||
case MSG_START:
|
||||
stopSelf(msg.arg2);
|
||||
break;
|
||||
case MSG_CONNECT:
|
||||
terminate = false;
|
||||
int connection_type;
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(OPTelemetryService.this);
|
||||
try {
|
||||
connection_type = Integer.decode(prefs.getString("connection_type", ""));
|
||||
} catch (NumberFormatException e) {
|
||||
connection_type = 0;
|
||||
}
|
||||
|
||||
switch(connection_type) {
|
||||
case 0: // No connection
|
||||
return;
|
||||
case 1:
|
||||
Toast.makeText(getApplicationContext(), "Attempting fake connection", Toast.LENGTH_SHORT).show();
|
||||
activeTelem = new FakeTelemetryThread();
|
||||
break;
|
||||
case 2:
|
||||
Toast.makeText(getApplicationContext(), "Attempting BT connection", Toast.LENGTH_SHORT).show();
|
||||
activeTelem = new BTTelemetryThread();
|
||||
break;
|
||||
case 3:
|
||||
Toast.makeText(getApplicationContext(), "Attempting TCP connection", Toast.LENGTH_SHORT).show();
|
||||
activeTelem = new TcpTelemetryThread();
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unsupported");
|
||||
}
|
||||
activeTelem.start();
|
||||
break;
|
||||
case MSG_DISCONNECT:
|
||||
Toast.makeText(getApplicationContext(), "Disconnect requested", Toast.LENGTH_SHORT).show();
|
||||
terminate = true;
|
||||
activeTelem.interrupt();
|
||||
try {
|
||||
activeTelem.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
activeTelem = null;
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(INTENT_ACTION_DISCONNECTED);
|
||||
sendBroadcast(intent,null);
|
||||
|
||||
stopSelf();
|
||||
|
||||
break;
|
||||
case MSG_TOAST:
|
||||
Toast.makeText(OPTelemetryService.this, (String) msg.obj, Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
default:
|
||||
System.out.println(msg.toString());
|
||||
throw new Error("Invalid message");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the service starts. It creates a thread to handle messages (e.g. connect and disconnect)
|
||||
* and based on the stored preference will send itself a connect signal if needed.
|
||||
*/
|
||||
public void startup() {
|
||||
Toast.makeText(getApplicationContext(), "Telemetry service starting", Toast.LENGTH_SHORT).show();
|
||||
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "startup()");
|
||||
|
||||
thread = new HandlerThread("TelemetryServiceHandler", Process.THREAD_PRIORITY_BACKGROUND);
|
||||
thread.start();
|
||||
|
||||
// Get the HandlerThread's Looper and use it for our Handler
|
||||
mServiceLooper = thread.getLooper();
|
||||
mServiceHandler = new ServiceHandler(mServiceLooper);
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(OPTelemetryService.this);
|
||||
if(prefs.getBoolean("autoconnect", false)) {
|
||||
Message msg = mServiceHandler.obtainMessage();
|
||||
msg.arg1 = MSG_CONNECT;
|
||||
msg.arg2 = 0;
|
||||
mServiceHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "Telemetry service created");
|
||||
startup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
// Currently only using as bound service
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "onStartCommand()");
|
||||
// If we get killed, after returning from here, restart
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "onBind()");
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Toast.makeText(this, "Telemetry service done", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public class LocalBinder extends Binder {
|
||||
public TelemTask getTelemTask(int id) {
|
||||
return (TelemTask) activeTelem;
|
||||
}
|
||||
public void openConnection() {
|
||||
Toast.makeText(getApplicationContext(), "Requested open connection", Toast.LENGTH_SHORT).show();
|
||||
Message msg = mServiceHandler.obtainMessage();
|
||||
msg.arg1 = MSG_CONNECT;
|
||||
mServiceHandler.sendMessage(msg);
|
||||
}
|
||||
public void stopConnection() {
|
||||
Message msg = mServiceHandler.obtainMessage();
|
||||
msg.arg1 = MSG_DISCONNECT;
|
||||
mServiceHandler.sendMessage(msg);
|
||||
}
|
||||
public boolean isConnected() {
|
||||
return activeTelem != null;
|
||||
}
|
||||
};
|
||||
|
||||
public void toastMessage(String msgText) {
|
||||
Message msg = mServiceHandler.obtainMessage();
|
||||
msg.arg1 = MSG_TOAST;
|
||||
msg.obj = msgText;
|
||||
mServiceHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used by other processes to get a handle to the object manager
|
||||
*/
|
||||
public interface TelemTask {
|
||||
public UAVObjectManager getObjectManager();
|
||||
};
|
||||
|
||||
// Fake class for testing, simply emits periodic updates on
|
||||
private class FakeTelemetryThread extends Thread implements TelemTask {
|
||||
private final UAVObjectManager objMngr;
|
||||
@Override
|
||||
public UAVObjectManager getObjectManager() { return objMngr; };
|
||||
|
||||
FakeTelemetryThread() {
|
||||
objMngr = new UAVObjectManager();
|
||||
UAVObjectsInitialize.register(objMngr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("Running fake thread");
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(INTENT_ACTION_CONNECTED);
|
||||
sendBroadcast(intent,null);
|
||||
|
||||
//toastMessage("Started fake telemetry thread");
|
||||
UAVDataObject systemStats = (UAVDataObject) objMngr.getObject("SystemStats");
|
||||
UAVDataObject attitudeActual = (UAVDataObject) objMngr.getObject("AttitudeActual");
|
||||
UAVDataObject homeLocation = (UAVDataObject) objMngr.getObject("HomeLocation");
|
||||
UAVDataObject positionActual = (UAVDataObject) objMngr.getObject("PositionActual");
|
||||
UAVDataObject systemAlarms = (UAVDataObject) objMngr.getObject("SystemAlarms");
|
||||
|
||||
systemAlarms.getField("Alarm").setValue("Warning",0);
|
||||
systemAlarms.getField("Alarm").setValue("OK",1);
|
||||
systemAlarms.getField("Alarm").setValue("Critical",2);
|
||||
systemAlarms.getField("Alarm").setValue("Error",3);
|
||||
systemAlarms.updated();
|
||||
|
||||
homeLocation.getField("Latitude").setDouble(379420315);
|
||||
homeLocation.getField("Longitude").setDouble(-88330078);
|
||||
homeLocation.getField("Be").setDouble(26702.78710938,0);
|
||||
homeLocation.getField("Be").setDouble(-1468.33605957,1);
|
||||
homeLocation.getField("Be").setDouble(34181.78515625,2);
|
||||
|
||||
|
||||
double roll = 0;
|
||||
double pitch = 0;
|
||||
double yaw = 0;
|
||||
double north = 0;
|
||||
double east = 0;
|
||||
while( !terminate ) {
|
||||
attitudeActual.getField("Roll").setDouble(roll);
|
||||
attitudeActual.getField("Pitch").setDouble(pitch);
|
||||
attitudeActual.getField("Yaw").setDouble(yaw);
|
||||
positionActual.getField("North").setDouble(north += 100);
|
||||
positionActual.getField("East").setDouble(east += 100);
|
||||
roll = (roll + 10) % 180;
|
||||
pitch = (pitch + 10) % 180;
|
||||
yaw = (yaw + 10) % 360;
|
||||
|
||||
systemStats.updated();
|
||||
attitudeActual.updated();
|
||||
positionActual.updated();
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private class BTTelemetryThread extends Thread implements TelemTask {
|
||||
|
||||
private final UAVObjectManager objMngr;
|
||||
private UAVTalk uavTalk;
|
||||
private Telemetry tel;
|
||||
private TelemetryMonitor mon;
|
||||
|
||||
@Override
|
||||
public UAVObjectManager getObjectManager() { return objMngr; };
|
||||
|
||||
BTTelemetryThread() {
|
||||
objMngr = new UAVObjectManager();
|
||||
UAVObjectsInitialize.register(objMngr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (DEBUG) Log.d(TAG, "Telemetry Thread started");
|
||||
|
||||
Looper.prepare();
|
||||
|
||||
BluetoothUAVTalk bt = new BluetoothUAVTalk(OPTelemetryService.this);
|
||||
for( int i = 0; i < 10; i++ ) {
|
||||
if (DEBUG) Log.d(TAG, "Attempting Bluetooth Connection");
|
||||
|
||||
bt.connect(objMngr);
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Done attempting connection");
|
||||
if( bt.getConnected() )
|
||||
break;
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Thread interrupted while trying to connect");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( ! bt.getConnected() ) {
|
||||
toastMessage("BT connection failed");
|
||||
return;
|
||||
}
|
||||
toastMessage("BT Connected");
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Connected via bluetooth");
|
||||
|
||||
uavTalk = bt.getUavtalk();
|
||||
tel = new Telemetry(uavTalk, objMngr);
|
||||
mon = new TelemetryMonitor(objMngr,tel);
|
||||
mon.addObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable arg0, Object arg1) {
|
||||
System.out.println("Mon updated. Connected: " + mon.getConnected() + " objects updated: " + mon.getObjectsUpdated());
|
||||
if(mon.getConnected() /*&& mon.getObjectsUpdated()*/) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(INTENT_ACTION_CONNECTED);
|
||||
sendBroadcast(intent,null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Entering UAVTalk processing loop");
|
||||
while( !terminate ) {
|
||||
try {
|
||||
if( !uavTalk.processInputStream() )
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
// This occurs when they communication stream fails
|
||||
toastMessage("Connection dropped");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "UAVTalk stream disconnected");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private class TcpTelemetryThread extends Thread implements TelemTask {
|
||||
|
||||
private final UAVObjectManager objMngr;
|
||||
private UAVTalk uavTalk;
|
||||
private Telemetry tel;
|
||||
private TelemetryMonitor mon;
|
||||
|
||||
@Override
|
||||
public UAVObjectManager getObjectManager() { return objMngr; };
|
||||
|
||||
TcpTelemetryThread() {
|
||||
objMngr = new UAVObjectManager();
|
||||
UAVObjectsInitialize.register(objMngr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (DEBUG) Log.d(TAG, "Telemetry Thread started");
|
||||
|
||||
Looper.prepare();
|
||||
|
||||
TcpUAVTalk tcp = new TcpUAVTalk(OPTelemetryService.this);
|
||||
for( int i = 0; i < 10; i++ ) {
|
||||
if (DEBUG) Log.d(TAG, "Attempting network Connection");
|
||||
|
||||
tcp.connect(objMngr);
|
||||
|
||||
if( tcp.getConnected() )
|
||||
|
||||
break;
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Thread interrupted while trying to connect");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( ! tcp.getConnected() || terminate ) {
|
||||
toastMessage("TCP connection failed");
|
||||
return;
|
||||
}
|
||||
toastMessage("TCP Connected");
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Connected via network");
|
||||
|
||||
uavTalk = tcp.getUavtalk();
|
||||
tel = new Telemetry(uavTalk, objMngr);
|
||||
mon = new TelemetryMonitor(objMngr,tel);
|
||||
mon.addObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable arg0, Object arg1) {
|
||||
System.out.println("Mon updated. Connected: " + mon.getConnected() + " objects updated: " + mon.getObjectsUpdated());
|
||||
if(mon.getConnected() /*&& mon.getObjectsUpdated()*/) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(INTENT_ACTION_CONNECTED);
|
||||
sendBroadcast(intent,null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Entering UAVTalk processing loop");
|
||||
while( !terminate ) {
|
||||
try {
|
||||
if( !uavTalk.processInputStream() )
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
toastMessage("TCP Stream interrupted");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Looper.myLooper().quit();
|
||||
|
||||
// Shut down all the attached
|
||||
mon.stopMonitor();
|
||||
mon = null;
|
||||
tel.stopTelemetry();
|
||||
tel = null;
|
||||
|
||||
// Finally close the stream if it is still open
|
||||
tcp.disconnect();
|
||||
|
||||
if (DEBUG) Log.d(TAG, "UAVTalk stream disconnected");
|
||||
toastMessage("TCP Thread finished");
|
||||
}
|
||||
|
||||
};
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file TcpUAVTalk.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief UAVTalk over TCP.
|
||||
* @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.telemetry;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
import org.openpilot.uavtalk.UAVTalk;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
public class TcpUAVTalk {
|
||||
private final String TAG = "TcpUAVTalk";
|
||||
public static int LOGLEVEL = 2;
|
||||
public static boolean WARN = LOGLEVEL > 1;
|
||||
public static boolean DEBUG = LOGLEVEL > 0;
|
||||
|
||||
// Temporarily define fixed device name
|
||||
private String ip_address = "1";
|
||||
private int port = 9001;
|
||||
|
||||
private UAVTalk uavTalk;
|
||||
private boolean connected;
|
||||
private Socket socket;
|
||||
|
||||
/**
|
||||
* Construct a TcpUAVTalk object attached to the OPTelemetryService. Gets the
|
||||
* connection settings from the preferences.
|
||||
*/
|
||||
public TcpUAVTalk(Context caller) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(caller);
|
||||
ip_address = prefs.getString("ip_address","127.0.0.1");
|
||||
try {
|
||||
port = Integer.decode(prefs.getString("port", ""));
|
||||
} catch (NumberFormatException e) {
|
||||
//TODO: Handle this exception
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Trying to open UAVTalk with " + ip_address);
|
||||
|
||||
connected = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect a TCP object to an object manager. Returns true if already
|
||||
* connected, otherwise returns true if managed a successful socket.
|
||||
*/
|
||||
public boolean connect(UAVObjectManager objMngr) {
|
||||
if( getConnected() )
|
||||
return true;
|
||||
if( !openTelemetryTcp(objMngr) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
socket = null;
|
||||
}
|
||||
|
||||
public boolean getConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
public UAVTalk getUavtalk() {
|
||||
return uavTalk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a TCP socket to the address determined on construction. If successful
|
||||
* creates a UAVTalk stream connection this socket to the passed in object manager
|
||||
*/
|
||||
private boolean openTelemetryTcp(UAVObjectManager objMngr) {
|
||||
Log.d(TAG, "Opening connection to " + ip_address + " at address " + port);
|
||||
|
||||
InetAddress serverAddr = null;
|
||||
try {
|
||||
serverAddr = InetAddress.getByName(ip_address);
|
||||
} catch (UnknownHostException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
socket = null;
|
||||
try {
|
||||
socket = new Socket(serverAddr,port);
|
||||
} catch (IOException e1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
connected = true;
|
||||
|
||||
try {
|
||||
uavTalk = new UAVTalk(socket.getInputStream(), socket.getOutputStream(), objMngr);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG,"Error starting UAVTalk");
|
||||
// TODO Auto-generated catch block
|
||||
//e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +1,27 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file Telemetry.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Port of Telemetry.cpp from the GCS. Handles transactions on the
|
||||
* UAVTalk channel.
|
||||
* @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.uavtalk;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -14,7 +38,7 @@ import java.util.TimerTask;
|
||||
import android.util.Log;
|
||||
|
||||
public class Telemetry {
|
||||
|
||||
|
||||
private final String TAG = "Telemetry";
|
||||
public static int LOGLEVEL = 0;
|
||||
public static boolean WARN = LOGLEVEL > 2;
|
||||
@ -31,7 +55,7 @@ public class Telemetry {
|
||||
public int rxErrors;
|
||||
public int txRetries;
|
||||
} ;
|
||||
|
||||
|
||||
class ObjectTimeInfo {
|
||||
UAVObject obj;
|
||||
int updatePeriodMs; /** Update period in ms or 0 if no periodic updates are needed */
|
||||
@ -51,7 +75,7 @@ public class Telemetry {
|
||||
int retriesRemaining;
|
||||
boolean acked;
|
||||
} ;
|
||||
|
||||
|
||||
/**
|
||||
* Events generated by objects. Not enum because used in mask.
|
||||
*/
|
||||
@ -59,7 +83,7 @@ public class Telemetry {
|
||||
private static final int EV_UPDATED = 0x02; /** Object data updated by changing the data structure */
|
||||
private static final int EV_UPDATED_MANUAL = 0x04; /** Object update event manually generated */
|
||||
private static final int EV_UPDATE_REQ = 0x08; /** Request to update object data */
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
@ -71,33 +95,36 @@ public class Telemetry {
|
||||
// Process all objects in the list
|
||||
List< List<UAVObject> > objs = objMngr.getObjects();
|
||||
ListIterator<List<UAVObject>> li = objs.listIterator();
|
||||
while(li.hasNext())
|
||||
while(li.hasNext())
|
||||
registerObject(li.next().get(0)); // we only need to register one instance per object type
|
||||
|
||||
// Listen to new object creations
|
||||
objMngr.addNewInstanceObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
newInstance((UAVObject) data);
|
||||
newInstance((UAVObject) data);
|
||||
}
|
||||
});
|
||||
objMngr.addNewObjectObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
newObject((UAVObject) data);
|
||||
}
|
||||
newObject((UAVObject) data);
|
||||
}
|
||||
});
|
||||
|
||||
// Listen to transaction completions
|
||||
utalk.addObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
try {
|
||||
transactionCompleted((UAVObject) data);
|
||||
} catch (IOException e) {
|
||||
// Disconnect when stream fails
|
||||
observable.deleteObserver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Get GCS stats object
|
||||
gcsStatsObj = objMngr.getObject("GCSTelemetryStats");
|
||||
|
||||
@ -110,16 +137,16 @@ public class Telemetry {
|
||||
txErrors = 0;
|
||||
txRetries = 0;
|
||||
}
|
||||
|
||||
|
||||
synchronized void transTimerSetPeriod(int periodMs) {
|
||||
if(transTimerTask != null)
|
||||
transTimerTask.cancel();
|
||||
|
||||
if(transTimer != null)
|
||||
|
||||
if(transTimer != null)
|
||||
transTimer.purge();
|
||||
|
||||
transTimer = new Timer();
|
||||
|
||||
|
||||
transTimerTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -128,11 +155,11 @@ public class Telemetry {
|
||||
} catch (IOException e) {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
transTimer.schedule(transTimerTask, periodMs, periodMs);
|
||||
}
|
||||
|
||||
|
||||
synchronized void updateTimerSetPeriod(int periodMs) {
|
||||
if (updateTimer != null) {
|
||||
updateTimer.cancel();
|
||||
@ -152,7 +179,7 @@ public class Telemetry {
|
||||
updateTimerTask.cancel();
|
||||
updateTimer.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
updateTimer.schedule(updateTimerTask, periodMs, periodMs);
|
||||
|
||||
@ -223,11 +250,12 @@ public class Telemetry {
|
||||
obj = li.next();
|
||||
//TODO: Disconnect all
|
||||
// obj.disconnect(this);
|
||||
|
||||
|
||||
// Connect only the selected events
|
||||
if ( (eventMask&EV_UNPACKED) != 0)
|
||||
{
|
||||
obj.addUnpackedObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
try {
|
||||
objectUnpacked( (UAVObject) data);
|
||||
@ -235,12 +263,13 @@ public class Telemetry {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if ( (eventMask&EV_UPDATED) != 0)
|
||||
{
|
||||
obj.addUpdatedAutoObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
try {
|
||||
objectUpdatedAuto( (UAVObject) data);
|
||||
@ -248,12 +277,13 @@ public class Telemetry {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if ( (eventMask&EV_UPDATED_MANUAL) != 0)
|
||||
{
|
||||
obj.addUpdatedManualObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
try {
|
||||
objectUpdatedManual( (UAVObject) data);
|
||||
@ -261,12 +291,13 @@ public class Telemetry {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if ( (eventMask&EV_UPDATE_REQ) != 0)
|
||||
{
|
||||
obj.addUpdateRequestedObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
try {
|
||||
updateRequested( (UAVObject) data);
|
||||
@ -274,7 +305,7 @@ public class Telemetry {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -331,7 +362,7 @@ public class Telemetry {
|
||||
|
||||
/**
|
||||
* Called when a transaction is successfully completed (uavtalk event)
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
private synchronized void transactionCompleted(UAVObject obj) throws IOException
|
||||
{
|
||||
@ -355,7 +386,7 @@ public class Telemetry {
|
||||
|
||||
/**
|
||||
* Called when a transaction is not completed within the timeout period (timer event)
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
private synchronized void transactionTimeout() throws IOException
|
||||
{
|
||||
@ -387,7 +418,7 @@ public class Telemetry {
|
||||
|
||||
/**
|
||||
* Start an object transaction with UAVTalk, all information is stored in transInfo
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
private synchronized void processObjectTransaction() throws IOException
|
||||
{
|
||||
@ -421,7 +452,7 @@ public class Telemetry {
|
||||
|
||||
/**
|
||||
* Process the event received from an object
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
private synchronized void processObjectUpdates(UAVObject obj, int event, boolean allInstances, boolean priority) throws IOException
|
||||
{
|
||||
@ -450,7 +481,7 @@ public class Telemetry {
|
||||
else
|
||||
{
|
||||
if ( objQueue.size() < MAX_QUEUE_SIZE )
|
||||
{
|
||||
{
|
||||
objQueue.add(objInfo);
|
||||
}
|
||||
else
|
||||
@ -469,7 +500,7 @@ public class Telemetry {
|
||||
|
||||
/**
|
||||
* Process events from the object queue
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
private synchronized void processObjectQueue() throws IOException
|
||||
{
|
||||
@ -536,7 +567,7 @@ public class Telemetry {
|
||||
}
|
||||
|
||||
// If this is a metaobject then make necessary telemetry updates
|
||||
if (objInfo.obj.isMetadata())
|
||||
if (objInfo.obj.isMetadata())
|
||||
{
|
||||
UAVMetaObject metaobj = (UAVMetaObject) objInfo.obj;
|
||||
updateObject( metaobj.getParentObject() );
|
||||
@ -554,11 +585,11 @@ public class Telemetry {
|
||||
/**
|
||||
* Check is any objects are pending for periodic updates
|
||||
* TODO: Clean-up
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
private synchronized void processPeriodicUpdates() throws IOException
|
||||
{
|
||||
|
||||
|
||||
if (DEBUG) Log.d(TAG, "processPeriodicUpdates()");
|
||||
// Stop timer
|
||||
updateTimer.cancel();
|
||||
@ -669,7 +700,7 @@ public class Telemetry {
|
||||
{
|
||||
registerObject(obj);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop all the telemetry timers
|
||||
*/
|
||||
@ -692,24 +723,24 @@ public class Telemetry {
|
||||
/**
|
||||
* Private variables
|
||||
*/
|
||||
private UAVObjectManager objMngr;
|
||||
private UAVTalk utalk;
|
||||
private final UAVObjectManager objMngr;
|
||||
private final UAVTalk utalk;
|
||||
private UAVObject gcsStatsObj;
|
||||
private List<ObjectTimeInfo> objList = new ArrayList<ObjectTimeInfo>();
|
||||
private Queue<ObjectQueueInfo> objQueue = new LinkedList<ObjectQueueInfo>();
|
||||
private Queue<ObjectQueueInfo> objPriorityQueue = new LinkedList<ObjectQueueInfo>();
|
||||
private ObjectTransactionInfo transInfo = new ObjectTransactionInfo();
|
||||
private final List<ObjectTimeInfo> objList = new ArrayList<ObjectTimeInfo>();
|
||||
private final Queue<ObjectQueueInfo> objQueue = new LinkedList<ObjectQueueInfo>();
|
||||
private final Queue<ObjectQueueInfo> objPriorityQueue = new LinkedList<ObjectQueueInfo>();
|
||||
private final ObjectTransactionInfo transInfo = new ObjectTransactionInfo();
|
||||
private boolean transPending;
|
||||
|
||||
|
||||
private Timer updateTimer;
|
||||
private TimerTask updateTimerTask;
|
||||
private Timer transTimer;
|
||||
private TimerTask transTimerTask;
|
||||
|
||||
|
||||
private int timeToNextUpdateMs;
|
||||
private int txErrors;
|
||||
private int txRetries;
|
||||
|
||||
|
||||
/**
|
||||
* Private constants
|
||||
*/
|
||||
@ -718,7 +749,7 @@ public class Telemetry {
|
||||
private static final int MAX_UPDATE_PERIOD_MS = 1000;
|
||||
private static final int MIN_UPDATE_PERIOD_MS = 1;
|
||||
private static final int MAX_QUEUE_SIZE = 20;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,28 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file TelemetryMonitor.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief High level monitoring of telemetry to handle connection and
|
||||
* disconnection and then signal the rest of the application.
|
||||
* This also makes sure to fetch all objects on initial connection.
|
||||
* @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.uavtalk;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -22,22 +47,22 @@ public class TelemetryMonitor extends Observable{
|
||||
static final int STATS_CONNECT_PERIOD_MS = 1000;
|
||||
static final int CONNECTION_TIMEOUT_MS = 8000;
|
||||
|
||||
private UAVObjectManager objMngr;
|
||||
private Telemetry tel;
|
||||
private final UAVObjectManager objMngr;
|
||||
private final Telemetry tel;
|
||||
// private UAVObject objPending;
|
||||
private UAVObject gcsStatsObj;
|
||||
private UAVObject flightStatsObj;
|
||||
private Timer periodicTask;
|
||||
private int currentPeriod;
|
||||
private long lastUpdateTime;
|
||||
private List<UAVObject> queue;
|
||||
|
||||
private final List<UAVObject> queue;
|
||||
|
||||
private boolean connected = false;
|
||||
private boolean objects_updated = false;
|
||||
|
||||
|
||||
public boolean getConnected() { return connected; };
|
||||
public boolean getObjectsUpdated() { return objects_updated; };
|
||||
|
||||
|
||||
public TelemetryMonitor(UAVObjectManager objMngr, Telemetry tel)
|
||||
{
|
||||
this.objMngr = objMngr;
|
||||
@ -50,6 +75,7 @@ public class TelemetryMonitor extends Observable{
|
||||
flightStatsObj = objMngr.getObject("FlightTelemetryStats");
|
||||
|
||||
flightStatsObj.addUpdatedObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
try {
|
||||
flightStatsUpdated((UAVObject) data);
|
||||
@ -59,7 +85,7 @@ public class TelemetryMonitor extends Observable{
|
||||
// or fix the stream?
|
||||
flightStatsObj.removeUpdatedObserver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Start update timer
|
||||
@ -68,17 +94,17 @@ public class TelemetryMonitor extends Observable{
|
||||
|
||||
/**
|
||||
* Initiate object retrieval, initialize queue with objects to be retrieved.
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized void startRetrievingObjects() throws IOException
|
||||
{
|
||||
if (DEBUG) Log.d(TAG, "Start retrieving objects");
|
||||
|
||||
|
||||
// Clear object queue
|
||||
queue.clear();
|
||||
// Get all objects, add metaobjects, settings and data objects with OnChange update mode to the queue
|
||||
List< List<UAVObject> > objs = objMngr.getObjects();
|
||||
|
||||
|
||||
ListIterator<List<UAVObject>> objListIterator = objs.listIterator();
|
||||
while( objListIterator.hasNext() )
|
||||
{
|
||||
@ -121,7 +147,7 @@ public class TelemetryMonitor extends Observable{
|
||||
|
||||
/**
|
||||
* Retrieve the next object in the queue
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized void retrieveNextObject() throws IOException
|
||||
{
|
||||
@ -136,16 +162,17 @@ public class TelemetryMonitor extends Observable{
|
||||
}
|
||||
// Get next object from the queue
|
||||
UAVObject obj = queue.remove(0);
|
||||
|
||||
|
||||
if(obj == null) {
|
||||
throw new Error("Got null object forom transaction queue");
|
||||
}
|
||||
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Retrieving object: " + obj.getName()) ;
|
||||
// Connect to object
|
||||
|
||||
|
||||
// TODO: Does this need to stay here permanently? This appears to be used for setup mainly
|
||||
obj.addTransactionCompleted(new Observer() {
|
||||
@Override
|
||||
public void update(Observable observable, Object data) {
|
||||
UAVObject.TransactionResult result = (UAVObject.TransactionResult) data;
|
||||
if (DEBUG) Log.d(TAG,"Got transaction completed event from " + result.obj.getName() + " status: " + result.success);
|
||||
@ -155,7 +182,7 @@ public class TelemetryMonitor extends Observable{
|
||||
// When the telemetry stream is broken disconnect these updates
|
||||
observable.deleteObserver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Request update
|
||||
@ -165,7 +192,7 @@ public class TelemetryMonitor extends Observable{
|
||||
|
||||
/**
|
||||
* Called by the retrieved object when a transaction is completed.
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized void transactionCompleted(UAVObject obj, boolean success) throws IOException
|
||||
{
|
||||
@ -175,12 +202,12 @@ public class TelemetryMonitor extends Observable{
|
||||
// TODO: Need to be able to disconnect signals
|
||||
//obj->disconnect(this);
|
||||
// objPending = null;
|
||||
|
||||
|
||||
if(!success) {
|
||||
//Log.e(TAG, "Transaction failed: " + obj.getName() + " sending again.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Process next object if telemetry is still available
|
||||
if ( ((String) gcsStatsObj.getField("Status").getValue()).compareTo("Connected") == 0 )
|
||||
{
|
||||
@ -194,7 +221,7 @@ public class TelemetryMonitor extends Observable{
|
||||
|
||||
/**
|
||||
* Called each time the flight stats object is updated by the autopilot
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized void flightStatsUpdated(UAVObject obj) throws IOException
|
||||
{
|
||||
@ -213,7 +240,7 @@ public class TelemetryMonitor extends Observable{
|
||||
private long lastStatsTime;
|
||||
/**
|
||||
* Called periodically to update the statistics and connection status.
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized void processStatsUpdates() throws IOException
|
||||
{
|
||||
@ -222,14 +249,14 @@ public class TelemetryMonitor extends Observable{
|
||||
Telemetry.TelemetryStats telStats = tel.getStats();
|
||||
|
||||
if (DEBUG) Log.d(TAG, "processStatsUpdates() - stats reset");
|
||||
|
||||
|
||||
// Need to compute time because this update is not regular enough
|
||||
float dT = (float) (System.currentTimeMillis() - lastStatsTime) / 1000.0f;
|
||||
float dT = (System.currentTimeMillis() - lastStatsTime) / 1000.0f;
|
||||
lastStatsTime = System.currentTimeMillis();
|
||||
|
||||
// Update stats object
|
||||
gcsStatsObj.getField("RxDataRate").setDouble( (float)telStats.rxBytes / dT );
|
||||
gcsStatsObj.getField("TxDataRate").setDouble( (float)telStats.txBytes / dT );
|
||||
// Update stats object
|
||||
gcsStatsObj.getField("RxDataRate").setDouble( telStats.rxBytes / dT );
|
||||
gcsStatsObj.getField("TxDataRate").setDouble( telStats.txBytes / dT );
|
||||
UAVObjectField field = gcsStatsObj.getField("RxFailures");
|
||||
field.setDouble(field.getDouble() + telStats.rxErrors);
|
||||
field = gcsStatsObj.getField("TxFailures");
|
||||
@ -240,7 +267,7 @@ public class TelemetryMonitor extends Observable{
|
||||
tel.resetStats();
|
||||
|
||||
if (DEBUG) Log.d(TAG, "processStatsUpdates() - stats updated");
|
||||
|
||||
|
||||
// Check for a connection timeout
|
||||
boolean connectionTimeout;
|
||||
if ( telStats.rxObjects > 0 )
|
||||
@ -266,7 +293,7 @@ public class TelemetryMonitor extends Observable{
|
||||
}
|
||||
UAVObjectField statusField = gcsStatsObj.getField("Status");
|
||||
String oldStatus = new String((String) statusField.getValue());
|
||||
|
||||
|
||||
if (DEBUG) Log.d(TAG,"GCS: " + statusField.getValue() + " Flight: " + flightStatsObj.getField("Status").getValue());
|
||||
|
||||
if ( oldStatus.compareTo("Disconnected") == 0 )
|
||||
@ -294,11 +321,11 @@ public class TelemetryMonitor extends Observable{
|
||||
|
||||
// Force telemetry update if not yet connected
|
||||
boolean gcsStatusChanged = !oldStatus.equals(statusField.getValue());
|
||||
|
||||
|
||||
boolean gcsConnected = statusField.getValue().equals("Connected");
|
||||
boolean gcsDisconnected = statusField.getValue().equals("Disconnected");
|
||||
boolean flightConnected = flightStatsObj.getField("Status").equals("Connected");
|
||||
|
||||
|
||||
if ( !gcsConnected || !flightConnected )
|
||||
{
|
||||
if (DEBUG) Log.d(TAG,"Sending gcs status");
|
||||
@ -323,7 +350,7 @@ public class TelemetryMonitor extends Observable{
|
||||
objects_updated = false;
|
||||
setChanged();
|
||||
}
|
||||
|
||||
|
||||
if (DEBUG) Log.d(TAG, "processStatsUpdates() - before notify");
|
||||
notifyObservers();
|
||||
if (DEBUG) Log.d(TAG, "processStatsUpdates() - after notify");
|
||||
@ -344,11 +371,11 @@ public class TelemetryMonitor extends Observable{
|
||||
} catch (IOException e) {
|
||||
// Once the stream has died stop trying to process these updates
|
||||
periodicTask.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, currentPeriod, currentPeriod);
|
||||
}
|
||||
|
||||
|
||||
public void stopMonitor()
|
||||
{
|
||||
periodicTask.cancel();
|
||||
|
@ -1,11 +1,34 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file UAVDataObject.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief The base object for all UAVO data.
|
||||
* @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.uavtalk;
|
||||
|
||||
public abstract class UAVDataObject extends UAVObject {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructor for UAVDataObject
|
||||
* @param objID the object id to be created
|
||||
* @param isSingleInst
|
||||
* @param isSingleInst
|
||||
* @param isSet
|
||||
* @param name
|
||||
*/
|
||||
@ -24,6 +47,7 @@ public abstract class UAVDataObject extends UAVObject {
|
||||
super.initialize(instID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMetadata() { return false; };
|
||||
/**
|
||||
* Assign a metaobject
|
||||
@ -45,6 +69,7 @@ public abstract class UAVDataObject extends UAVObject {
|
||||
/**
|
||||
* Set the object's metadata
|
||||
*/
|
||||
@Override
|
||||
public void setMetadata(Metadata mdata)
|
||||
{
|
||||
if ( mobj != null )
|
||||
@ -56,6 +81,7 @@ public abstract class UAVDataObject extends UAVObject {
|
||||
/**
|
||||
* Get the object's metadata
|
||||
*/
|
||||
@Override
|
||||
public Metadata getMetadata()
|
||||
{
|
||||
if ( mobj != null)
|
||||
@ -75,13 +101,13 @@ public abstract class UAVDataObject extends UAVObject {
|
||||
{
|
||||
return mobj;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Make abstract
|
||||
public UAVDataObject clone(long instID) {
|
||||
return (UAVDataObject) super.clone();
|
||||
}
|
||||
|
||||
|
||||
private UAVMetaObject mobj;
|
||||
private boolean isSet;
|
||||
private final boolean isSet;
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,26 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file UAVMetaObject.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Base object for all UAVO meta data
|
||||
* @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.uavtalk;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@ -10,7 +33,7 @@ public class UAVMetaObject extends UAVObject {
|
||||
public UAVMetaObject(long objID, String name, UAVDataObject parent) throws Exception {
|
||||
super(objID, true, name);
|
||||
this.parent = parent;
|
||||
|
||||
|
||||
ownMetadata = new Metadata();
|
||||
|
||||
ownMetadata.flags = 0; // TODO: Fix flags
|
||||
@ -27,7 +50,7 @@ public class UAVMetaObject extends UAVObject {
|
||||
modesBitField.add("FlightUpdateOnChange");
|
||||
modesBitField.add("GCSUpdatePeriodic");
|
||||
modesBitField.add("GCSUpdateOnChange");
|
||||
|
||||
|
||||
List<UAVObjectField> fields = new ArrayList<UAVObjectField>();
|
||||
fields.add( new UAVObjectField("Modes", "", UAVObjectField.FieldType.BITFIELD, 1, modesBitField) );
|
||||
fields.add( new UAVObjectField("Flight Telemetry Update Period", "ms", UAVObjectField.FieldType.UINT16, 1, null) );
|
||||
@ -47,12 +70,12 @@ public class UAVMetaObject extends UAVObject {
|
||||
initializeFields(fields, ByteBuffer.allocate(numBytes), numBytes);
|
||||
|
||||
// Setup metadata of parent
|
||||
parentMetadata = parent.getDefaultMetadata();
|
||||
parentMetadata = parent.getDefaultMetadata();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isMetadata() {
|
||||
return true;
|
||||
public boolean isMetadata() {
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -67,6 +90,7 @@ public class UAVMetaObject extends UAVObject {
|
||||
* Set the metadata of the metaobject, this function will
|
||||
* do nothing since metaobjects have read-only metadata.
|
||||
*/
|
||||
@Override
|
||||
public void setMetadata(Metadata mdata)
|
||||
{
|
||||
return; // can not update metaobject's metadata
|
||||
@ -75,6 +99,7 @@ public class UAVMetaObject extends UAVObject {
|
||||
/**
|
||||
* Get the metadata of the metaobject
|
||||
*/
|
||||
@Override
|
||||
public Metadata getMetadata()
|
||||
{
|
||||
return ownMetadata;
|
||||
@ -83,6 +108,7 @@ public class UAVMetaObject extends UAVObject {
|
||||
/**
|
||||
* Get the default metadata
|
||||
*/
|
||||
@Override
|
||||
public Metadata getDefaultMetadata()
|
||||
{
|
||||
return ownMetadata;
|
||||
@ -110,8 +136,8 @@ public class UAVMetaObject extends UAVObject {
|
||||
}
|
||||
|
||||
|
||||
private UAVObject parent;
|
||||
private Metadata ownMetadata;
|
||||
private final UAVObject parent;
|
||||
private final Metadata ownMetadata;
|
||||
private Metadata parentMetadata;
|
||||
|
||||
|
||||
|
@ -1,17 +1,40 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file UAVObject.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Base object for UAVDataObject and UAVMetaObject.
|
||||
* @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.uavtalk;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Observer;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
public abstract class UAVObject {
|
||||
|
||||
public class CallbackListener extends Observable {
|
||||
private UAVObject parent;
|
||||
|
||||
|
||||
public class CallbackListener extends Observable {
|
||||
private final UAVObject parent;
|
||||
|
||||
public CallbackListener(UAVObject parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
@ -29,7 +52,7 @@ public abstract class UAVObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class TransactionResult {
|
||||
public UAVObject obj;
|
||||
public boolean success;
|
||||
@ -38,8 +61,8 @@ public abstract class UAVObject {
|
||||
this.success = success;
|
||||
}
|
||||
}
|
||||
|
||||
private CallbackListener transactionCompletedListeners = new CallbackListener(this);
|
||||
|
||||
private final CallbackListener transactionCompletedListeners = new CallbackListener(this);
|
||||
public void addTransactionCompleted(Observer o) {
|
||||
synchronized(transactionCompletedListeners) {
|
||||
transactionCompletedListeners.addObserver(o);
|
||||
@ -55,8 +78,8 @@ public abstract class UAVObject {
|
||||
transactionCompletedListeners.event(new TransactionResult(this,status));
|
||||
}
|
||||
}
|
||||
|
||||
private CallbackListener updatedListeners = new CallbackListener(this);
|
||||
|
||||
private final CallbackListener updatedListeners = new CallbackListener(this);
|
||||
public void removeUpdatedObserver(Observer o) {
|
||||
synchronized(updatedListeners) {
|
||||
updatedListeners.deleteObserver(o);
|
||||
@ -75,8 +98,8 @@ public abstract class UAVObject {
|
||||
updatedManual();
|
||||
}
|
||||
public void updated() { updated(true); };
|
||||
|
||||
private CallbackListener unpackedListeners = new CallbackListener(this);
|
||||
|
||||
private final CallbackListener unpackedListeners = new CallbackListener(this);
|
||||
public void addUnpackedObserver(Observer o) {
|
||||
synchronized(unpackedListeners) {
|
||||
unpackedListeners.addObserver(o);
|
||||
@ -88,7 +111,7 @@ public abstract class UAVObject {
|
||||
}
|
||||
}
|
||||
|
||||
private CallbackListener updatedAutoListeners = new CallbackListener(this);
|
||||
private final CallbackListener updatedAutoListeners = new CallbackListener(this);
|
||||
public void addUpdatedAutoObserver(Observer o) {
|
||||
synchronized(updatedAutoListeners) {
|
||||
updatedAutoListeners.addObserver(o);
|
||||
@ -100,7 +123,7 @@ public abstract class UAVObject {
|
||||
}
|
||||
}
|
||||
|
||||
private CallbackListener updatedManualListeners = new CallbackListener(this);
|
||||
private final CallbackListener updatedManualListeners = new CallbackListener(this);
|
||||
public void addUpdatedManualObserver(Observer o) {
|
||||
synchronized(updatedManualListeners) {
|
||||
updatedManualListeners.addObserver(o);
|
||||
@ -112,7 +135,7 @@ public abstract class UAVObject {
|
||||
}
|
||||
}
|
||||
|
||||
private CallbackListener updateRequestedListeners = new CallbackListener(this);
|
||||
private final CallbackListener updateRequestedListeners = new CallbackListener(this);
|
||||
public void addUpdateRequestedObserver(Observer o) {
|
||||
synchronized(updateRequestedListeners) {
|
||||
updateRequestedListeners.addObserver(o);
|
||||
@ -125,7 +148,7 @@ public abstract class UAVObject {
|
||||
}
|
||||
|
||||
public abstract boolean isMetadata();
|
||||
|
||||
|
||||
/**
|
||||
* Object update mode
|
||||
*/
|
||||
@ -172,10 +195,10 @@ public abstract class UAVObject {
|
||||
|
||||
/** Update period used by the telemetry module (only if telemetry mode is PERIODIC) */
|
||||
public int flightTelemetryUpdatePeriod;
|
||||
|
||||
|
||||
/** Update period used by the GCS (only if telemetry mode is PERIODIC) */
|
||||
public int gcsTelemetryUpdatePeriod;
|
||||
|
||||
|
||||
/** Update period used by the GCS (only if telemetry mode is PERIODIC) */
|
||||
public int loggingUpdatePeriod;
|
||||
/**
|
||||
@ -194,7 +217,7 @@ public abstract class UAVObject {
|
||||
private void SET_BITS(int shift, int value, int mask) {
|
||||
this.flags = (this.flags & ~(mask << shift)) | (value << shift);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the UAVObject metadata access member
|
||||
* \return the access type
|
||||
@ -219,7 +242,7 @@ public abstract class UAVObject {
|
||||
* \return the GCS access type
|
||||
*/
|
||||
public AccessMode GetGcsAccess()
|
||||
{
|
||||
{
|
||||
return AccessModeEnum((this.flags >> UAVOBJ_GCS_ACCESS_SHIFT) & 1);
|
||||
}
|
||||
|
||||
@ -382,7 +405,7 @@ public abstract class UAVObject {
|
||||
|
||||
/**
|
||||
* Initialize objects' data fields
|
||||
*
|
||||
*
|
||||
* @param fields
|
||||
* List of fields held by the object
|
||||
* @param data
|
||||
@ -434,7 +457,7 @@ public abstract class UAVObject {
|
||||
|
||||
/**
|
||||
* Get the description of the object
|
||||
*
|
||||
*
|
||||
* @return The description of the object
|
||||
*/
|
||||
public String getDescription() {
|
||||
@ -443,7 +466,7 @@ public abstract class UAVObject {
|
||||
|
||||
/**
|
||||
* Set the description of the object
|
||||
*
|
||||
*
|
||||
* @param The
|
||||
* description of the object
|
||||
* @return
|
||||
@ -525,7 +548,7 @@ public abstract class UAVObject {
|
||||
|
||||
/**
|
||||
* Get a specific field
|
||||
*
|
||||
*
|
||||
* @throws Exception
|
||||
* @returns The field or NULL if not found
|
||||
*/
|
||||
@ -543,7 +566,7 @@ public abstract class UAVObject {
|
||||
|
||||
/**
|
||||
* Pack the object data into a byte array
|
||||
*
|
||||
*
|
||||
* @param dataOut
|
||||
* ByteBuffer to receive the data.
|
||||
* @throws Exception
|
||||
@ -565,7 +588,7 @@ public abstract class UAVObject {
|
||||
|
||||
/**
|
||||
* Unpack the object data from a byte array
|
||||
*
|
||||
*
|
||||
* @param dataIn
|
||||
* The ByteBuffer to pull data from
|
||||
* @throws Exception
|
||||
@ -582,11 +605,11 @@ public abstract class UAVObject {
|
||||
UAVObjectField field = li.next();
|
||||
numBytes += field.unpack(dataIn);
|
||||
}
|
||||
|
||||
|
||||
// Trigger all the listeners for the unpack event
|
||||
unpacked();
|
||||
updated(false);
|
||||
|
||||
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
@ -774,6 +797,7 @@ public abstract class UAVObject {
|
||||
/**
|
||||
* Java specific functions
|
||||
*/
|
||||
@Override
|
||||
public synchronized UAVObject clone() {
|
||||
UAVObject newObj = clone();
|
||||
List<UAVObjectField> newFields = new ArrayList<UAVObjectField>();
|
||||
|
@ -1,3 +1,26 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file Telemetry.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Implementation of all the UAVObjectFields.
|
||||
* @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.uavtalk;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@ -6,7 +29,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UAVObjectField {
|
||||
|
||||
|
||||
public enum FieldType { INT8, INT16, INT32, UINT8, UINT16, UINT32, FLOAT32, ENUM, BITFIELD, STRING };
|
||||
|
||||
public UAVObjectField(String name, String units, FieldType type, int numElements, List<String> options) {
|
||||
@ -17,26 +40,26 @@ public class UAVObjectField {
|
||||
elementNames.add(String.valueOf(n));
|
||||
}
|
||||
// Initialize
|
||||
constructorInitialize(name, units, type, elementNames, options);
|
||||
constructorInitialize(name, units, type, elementNames, options);
|
||||
}
|
||||
|
||||
|
||||
public UAVObjectField(String name, String units, FieldType type, List<String> elementNames, List<String> options) {
|
||||
constructorInitialize(name, units, type, elementNames, options);
|
||||
}
|
||||
|
||||
|
||||
public void initialize(UAVObject obj){
|
||||
this.obj = obj;
|
||||
//clear();
|
||||
//clear();
|
||||
}
|
||||
|
||||
|
||||
public UAVObject getObject() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
public FieldType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
public String getTypeAsString() {
|
||||
switch (type)
|
||||
{
|
||||
@ -62,31 +85,31 @@ public class UAVObjectField {
|
||||
return "string";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public String getUnits() {
|
||||
return units;
|
||||
}
|
||||
|
||||
|
||||
public int getNumElements() {
|
||||
return numElements;
|
||||
}
|
||||
|
||||
|
||||
public List<String> getElementNames() {
|
||||
return elementNames;
|
||||
return elementNames;
|
||||
}
|
||||
|
||||
|
||||
public List<String> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function copies this field from the internal storage of the parent object
|
||||
* This function copies this field from the internal storage of the parent object
|
||||
* to a new ByteBuffer for UAVTalk. It also converts from the java standard (big endian)
|
||||
* to the arm/uavtalk standard (little endian)
|
||||
* @param dataOut
|
||||
@ -98,7 +121,7 @@ public class UAVObjectField {
|
||||
dataOut.order(ByteOrder.LITTLE_ENDIAN);
|
||||
switch (type)
|
||||
{
|
||||
case INT8:
|
||||
case INT8:
|
||||
for (int index = 0; index < numElements; ++index) {
|
||||
Integer val = (Integer) getValue(index);
|
||||
dataOut.put(val.byteValue());
|
||||
@ -116,7 +139,7 @@ public class UAVObjectField {
|
||||
dataOut.putInt(val);
|
||||
}
|
||||
break;
|
||||
case UINT8:
|
||||
case UINT8:
|
||||
// TODO: Deal properly with unsigned
|
||||
for (int index = 0; index < numElements; ++index) {
|
||||
Integer val = (Integer) getValue(index);
|
||||
@ -144,7 +167,7 @@ public class UAVObjectField {
|
||||
case ENUM:
|
||||
List<Byte> l = (List<Byte>) data;
|
||||
for (int index = 0; index < numElements; ++index)
|
||||
dataOut.put((Byte) l.get(index));
|
||||
dataOut.put(l.get(index));
|
||||
break;
|
||||
case BITFIELD:
|
||||
for (int index = 0; index < numElements; ++index) {
|
||||
@ -156,9 +179,9 @@ public class UAVObjectField {
|
||||
throw new Error("Strings not yet implemented");
|
||||
}
|
||||
// Done
|
||||
return getNumBytes();
|
||||
return getNumBytes();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized int unpack(ByteBuffer dataIn) {
|
||||
// Unpack each element from input buffer
|
||||
@ -196,7 +219,7 @@ public class UAVObjectField {
|
||||
{
|
||||
List<Short> l = (List<Short>) this.data;
|
||||
for (int index = 0 ; index < numElements; ++index) {
|
||||
int signedval = (int) dataIn.get(); // this sign extends it
|
||||
int signedval = dataIn.get(); // this sign extends it
|
||||
int unsignedval = signedval & 0xff; // drop sign extension
|
||||
l.set(index, (short) unsignedval);
|
||||
}
|
||||
@ -206,7 +229,7 @@ public class UAVObjectField {
|
||||
{
|
||||
List<Integer> l = (List<Integer>) this.data;
|
||||
for (int index = 0 ; index < numElements; ++index) {
|
||||
int signedval = (int) dataIn.getShort(); // this sign extends it
|
||||
int signedval = dataIn.getShort(); // this sign extends it
|
||||
int unsignedval = signedval & 0xffff; // drop sign extension
|
||||
l.set(index, unsignedval);
|
||||
}
|
||||
@ -216,7 +239,7 @@ public class UAVObjectField {
|
||||
{
|
||||
List<Long> l = (List<Long>) this.data;
|
||||
for (int index = 0 ; index < numElements; ++index) {
|
||||
long signedval = (long) dataIn.getInt(); // this sign extends it
|
||||
long signedval = dataIn.getInt(); // this sign extends it
|
||||
long unsignedval = signedval & 0xffffffffL; // drop sign extension
|
||||
l.set(index, unsignedval);
|
||||
}
|
||||
@ -235,7 +258,7 @@ public class UAVObjectField {
|
||||
{
|
||||
List<Short> l = (List<Short>) this.data;
|
||||
for (int index = 0 ; index < numElements; ++index) {
|
||||
int signedval = (int) dataIn.get(); // this sign extends it
|
||||
int signedval = dataIn.get(); // this sign extends it
|
||||
int unsignedval = signedval & 0xff; // drop sign extension
|
||||
l.set(index, (short) unsignedval);
|
||||
}
|
||||
@ -254,9 +277,9 @@ public class UAVObjectField {
|
||||
//throw new Exception("Strings not handled");
|
||||
}
|
||||
// Done
|
||||
return getNumBytes();
|
||||
return getNumBytes();
|
||||
}
|
||||
|
||||
|
||||
public Object getValue() { return getValue(0); };
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized Object getValue(int index) {
|
||||
@ -265,7 +288,7 @@ public class UAVObjectField {
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case INT8:
|
||||
@ -287,7 +310,7 @@ public class UAVObjectField {
|
||||
List<Byte> l = (List<Byte>) data;
|
||||
Byte val = l.get(index);
|
||||
|
||||
//if(val >= options.size() || val < 0)
|
||||
//if(val >= options.size() || val < 0)
|
||||
// throw new Exception("Invalid value for" + name);
|
||||
|
||||
return options.get(val);
|
||||
@ -301,10 +324,10 @@ public class UAVObjectField {
|
||||
}
|
||||
}
|
||||
// If this point is reached then we got an invalid type
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setValue(Object data) { setValue(data,0); }
|
||||
|
||||
public void setValue(Object data) { setValue(data,0); }
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized void setValue(Object data, int index) {
|
||||
// Check that index is not out of bounds
|
||||
@ -361,15 +384,15 @@ public class UAVObjectField {
|
||||
break;
|
||||
}
|
||||
case ENUM:
|
||||
{
|
||||
{
|
||||
byte val;
|
||||
try {
|
||||
// Test if numeric constant passed in
|
||||
val = ((Number) data).byteValue();
|
||||
} catch (Exception e) {
|
||||
val = (byte) options.indexOf((String) data);
|
||||
val = (byte) options.indexOf(data);
|
||||
}
|
||||
//if(val < 0) throw new Exception("Enumerated value not found");
|
||||
//if(val < 0) throw new Exception("Enumerated value not found");
|
||||
List<Byte> l = (List<Byte>) this.data;
|
||||
l.set(index, val);
|
||||
break;
|
||||
@ -380,7 +403,7 @@ public class UAVObjectField {
|
||||
l.set(index, bound(data).shortValue());
|
||||
break;
|
||||
}
|
||||
case STRING:
|
||||
case STRING:
|
||||
{
|
||||
//throw new Exception("Sorry I haven't implemented strings yet");
|
||||
}
|
||||
@ -388,7 +411,7 @@ public class UAVObjectField {
|
||||
//obj.updated();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public double getDouble() { return getDouble(0); };
|
||||
@SuppressWarnings("unchecked")
|
||||
public double getDouble(int index) {
|
||||
@ -400,24 +423,24 @@ public class UAVObjectField {
|
||||
}
|
||||
return ((Number) getValue(index)).doubleValue();
|
||||
}
|
||||
|
||||
|
||||
public void setDouble(double value) { setDouble(value, 0); };
|
||||
public void setDouble(double value, int index) {
|
||||
setValue(value, index);
|
||||
}
|
||||
|
||||
|
||||
public int getDataOffset() {
|
||||
return offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
public int getNumBytes() {
|
||||
return numBytesPerElement * numElements;
|
||||
}
|
||||
|
||||
|
||||
public int getNumBytesElement() {
|
||||
return numBytesPerElement;
|
||||
}
|
||||
|
||||
|
||||
public boolean isNumeric() {
|
||||
switch (type)
|
||||
{
|
||||
@ -443,9 +466,9 @@ public class UAVObjectField {
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isText() {
|
||||
switch (type)
|
||||
{
|
||||
@ -471,9 +494,10 @@ public class UAVObjectField {
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String sout = new String();
|
||||
sout += name + ": ";
|
||||
@ -484,15 +508,15 @@ public class UAVObjectField {
|
||||
else
|
||||
sout += " ";
|
||||
}
|
||||
if (units.length() > 0)
|
||||
if (units.length() > 0)
|
||||
sout += " (" + units + ")\n";
|
||||
else
|
||||
sout += "\n";
|
||||
return sout;
|
||||
return sout;
|
||||
}
|
||||
|
||||
void fieldUpdated(UAVObjectField field) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -555,7 +579,7 @@ public class UAVObjectField {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized void constructorInitialize(String name, String units, FieldType type, List<String> elementNames, List<String> options) {
|
||||
// Copy params
|
||||
this.name = name;
|
||||
@ -572,43 +596,43 @@ public class UAVObjectField {
|
||||
switch (type)
|
||||
{
|
||||
case INT8:
|
||||
data = (Object) new ArrayList<Byte>(this.numElements);
|
||||
data = new ArrayList<Byte>(this.numElements);
|
||||
numBytesPerElement = 1;
|
||||
break;
|
||||
case INT16:
|
||||
data = (Object) new ArrayList<Short>(this.numElements);
|
||||
data = new ArrayList<Short>(this.numElements);
|
||||
numBytesPerElement = 2;
|
||||
break;
|
||||
case INT32:
|
||||
data = (Object) new ArrayList<Integer>(this.numElements);
|
||||
data = new ArrayList<Integer>(this.numElements);
|
||||
numBytesPerElement = 4;
|
||||
break;
|
||||
case UINT8:
|
||||
data = (Object) new ArrayList<Short>(this.numElements);
|
||||
data = new ArrayList<Short>(this.numElements);
|
||||
numBytesPerElement = 1;
|
||||
break;
|
||||
case UINT16:
|
||||
data = (Object) new ArrayList<Integer>(this.numElements);
|
||||
data = new ArrayList<Integer>(this.numElements);
|
||||
numBytesPerElement = 2;
|
||||
break;
|
||||
case UINT32:
|
||||
data = (Object) new ArrayList<Long>(this.numElements);
|
||||
data = new ArrayList<Long>(this.numElements);
|
||||
numBytesPerElement = 4;
|
||||
break;
|
||||
case FLOAT32:
|
||||
data = (Object) new ArrayList<Float>(this.numElements);
|
||||
data = new ArrayList<Float>(this.numElements);
|
||||
numBytesPerElement = 4;
|
||||
break;
|
||||
case ENUM:
|
||||
data = (Object) new ArrayList<Byte>(this.numElements);
|
||||
data = new ArrayList<Byte>(this.numElements);
|
||||
numBytesPerElement = 1;
|
||||
break;
|
||||
case BITFIELD:
|
||||
data = (Object) new ArrayList<Short>(this.numElements);
|
||||
data = new ArrayList<Short>(this.numElements);
|
||||
numBytesPerElement = 1;
|
||||
break;
|
||||
case STRING:
|
||||
data = (Object) new ArrayList<String>(this.numElements);
|
||||
data = new ArrayList<String>(this.numElements);
|
||||
numBytesPerElement = 1;
|
||||
break;
|
||||
default:
|
||||
@ -616,7 +640,7 @@ public class UAVObjectField {
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For numerical types bounds the data appropriately
|
||||
* @param val Can be any object, for numerical tries to cast to Number
|
||||
@ -624,7 +648,7 @@ public class UAVObjectField {
|
||||
* @note This is mostly needed because java has no unsigned integer
|
||||
*/
|
||||
protected Long bound (Object val) {
|
||||
|
||||
|
||||
switch(type) {
|
||||
case ENUM:
|
||||
case STRING:
|
||||
@ -679,15 +703,15 @@ public class UAVObjectField {
|
||||
return (long) 255;
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UAVObjectField clone()
|
||||
{
|
||||
UAVObjectField newField = new UAVObjectField(new String(name), new String(units), type,
|
||||
new ArrayList<String>(elementNames),
|
||||
UAVObjectField newField = new UAVObjectField(new String(name), new String(units), type,
|
||||
new ArrayList<String>(elementNames),
|
||||
new ArrayList<String>(options));
|
||||
newField.initialize(obj);
|
||||
newField.data = data;
|
||||
|
@ -1,3 +1,28 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file UAVObjectManager.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief Critical class. This is the data store for all UAVOs. Allows
|
||||
* other objects to access and change this data. Takes care of
|
||||
* propagating changes to the UAV.
|
||||
* @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.uavtalk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -8,19 +33,19 @@ import java.util.Observer;
|
||||
|
||||
public class UAVObjectManager {
|
||||
|
||||
public class CallbackListener extends Observable {
|
||||
public class CallbackListener extends Observable {
|
||||
public void event (UAVObject obj) {
|
||||
setChanged();
|
||||
notifyObservers(obj);
|
||||
}
|
||||
}
|
||||
private CallbackListener newInstance = new CallbackListener();
|
||||
private final CallbackListener newInstance = new CallbackListener();
|
||||
public void addNewInstanceObserver(Observer o) {
|
||||
synchronized(newInstance) {
|
||||
newInstance.addObserver(o);
|
||||
}
|
||||
}
|
||||
private CallbackListener newObject = new CallbackListener();
|
||||
private final CallbackListener newObject = new CallbackListener();
|
||||
public void addNewObjectObserver(Observer o) {
|
||||
synchronized(newObject) {
|
||||
newObject.addObserver(o);
|
||||
@ -29,7 +54,7 @@ public class UAVObjectManager {
|
||||
private final int MAX_INSTANCES = 10;
|
||||
|
||||
// Use array list to store objects since rarely added or deleted
|
||||
private List<List<UAVObject>> objects = new ArrayList<List<UAVObject>>();
|
||||
private final List<List<UAVObject>> objects = new ArrayList<List<UAVObject>>();
|
||||
|
||||
public UAVObjectManager()
|
||||
{
|
||||
@ -41,7 +66,7 @@ public class UAVObjectManager {
|
||||
* A new instance can be created directly by instantiating a new object or by calling clone() of
|
||||
* an existing object. The object will be registered and will be properly initialized so that it can accept
|
||||
* updates.
|
||||
* @throws Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public synchronized boolean registerObject(UAVDataObject obj) throws Exception
|
||||
{
|
||||
@ -61,7 +86,7 @@ public class UAVObjectManager {
|
||||
}
|
||||
// The object type has alredy been added, so now we need to initialize the new instance with the appropriate id
|
||||
// There is a single metaobject for all object instances of this type, so no need to create a new one
|
||||
// Get object type metaobject from existing instance
|
||||
// Get object type metaobject from existing instance
|
||||
UAVDataObject refObj = (UAVDataObject) instList.get(0);
|
||||
if (refObj == null)
|
||||
{
|
||||
@ -74,7 +99,7 @@ public class UAVObjectManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If InstID is zero then we find the next open instId and create it
|
||||
// If InstID is zero then we find the next open instId and create it
|
||||
if (obj.getInstID() == 0)
|
||||
{
|
||||
// Assign the next available ID and initialize the object instance the nadd
|
||||
@ -183,13 +208,13 @@ public class UAVObjectManager {
|
||||
// If no instances skip
|
||||
if(instList.size() == 0)
|
||||
continue;
|
||||
|
||||
|
||||
// If meta data skip
|
||||
if(instList.get(0).isMetadata())
|
||||
continue;
|
||||
|
||||
List<UAVDataObject> newInstList = new ArrayList<UAVDataObject>();
|
||||
ListIterator<UAVObject> instIt = instList.listIterator();
|
||||
|
||||
List<UAVDataObject> newInstList = new ArrayList<UAVDataObject>();
|
||||
ListIterator<UAVObject> instIt = instList.listIterator();
|
||||
while(instIt.hasNext()) {
|
||||
newInstList.add((UAVDataObject) instIt.next());
|
||||
}
|
||||
@ -216,13 +241,13 @@ public class UAVObjectManager {
|
||||
// If no instances skip
|
||||
if(instList.size() == 0)
|
||||
continue;
|
||||
|
||||
|
||||
// If meta data skip
|
||||
if(!instList.get(0).isMetadata())
|
||||
continue;
|
||||
|
||||
List<UAVMetaObject> newInstList = new ArrayList<UAVMetaObject>();
|
||||
ListIterator<UAVObject> instIt = instList.listIterator();
|
||||
|
||||
List<UAVMetaObject> newInstList = new ArrayList<UAVMetaObject>();
|
||||
ListIterator<UAVObject> instIt = instList.listIterator();
|
||||
while(instIt.hasNext()) {
|
||||
newInstList.add((UAVMetaObject) instIt.next());
|
||||
}
|
||||
@ -232,17 +257,17 @@ public class UAVObjectManager {
|
||||
return mObjects;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a specific object by name only, returns instance ID zero
|
||||
* @param name The object name
|
||||
* @return The object or null if not found
|
||||
*/
|
||||
public UAVObject getObject(String name)
|
||||
public UAVObject getObject(String name)
|
||||
{
|
||||
return getObject(name, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a specific object given its name and instance ID
|
||||
* @returns The object is found or NULL if not
|
||||
@ -257,11 +282,11 @@ public class UAVObjectManager {
|
||||
* @param objId the object id
|
||||
* @returns The object is found or NULL if not
|
||||
*/
|
||||
public UAVObject getObject(long objId)
|
||||
public UAVObject getObject(long objId)
|
||||
{
|
||||
return getObject(null, objId, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a specific object given its object and instance ID
|
||||
* @returns The object is found or NULL if not
|
||||
@ -293,7 +318,7 @@ public class UAVObjectManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -327,8 +352,8 @@ public class UAVObjectManager {
|
||||
return instList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,29 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file UAVTalk.java
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||
* @brief The protocol layer implementation of UAVTalk. Serializes objects
|
||||
* for transmission (which is done in the object itself which is aware
|
||||
* of byte packing) wraps that in the UAVTalk packet. Parses UAVTalk
|
||||
* packets and updates the UAVObjectManager.
|
||||
* @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.uavtalk;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -17,7 +43,7 @@ public class UAVTalk extends Observable {
|
||||
public static boolean DEBUG = LOGLEVEL > 0;
|
||||
|
||||
private Thread inputProcessingThread = null;
|
||||
|
||||
|
||||
/**
|
||||
* A reference to the thread for processing the incoming stream. Currently this method is ONLY
|
||||
* used for unit testing
|
||||
@ -26,6 +52,7 @@ public class UAVTalk extends Observable {
|
||||
if (inputProcessingThread == null)
|
||||
|
||||
inputProcessingThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
while(true) {
|
||||
try {
|
||||
@ -179,7 +206,7 @@ public class UAVTalk extends Observable {
|
||||
|
||||
/**
|
||||
* Process any data in the queue
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean processInputStream() throws IOException {
|
||||
int val;
|
||||
@ -195,13 +222,13 @@ public class UAVTalk extends Observable {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Request an update for the specified object, on success the object data
|
||||
* would have been updated by the GCS. \param[in] obj Object to update
|
||||
* \param[in] allInstances If set true then all instances will be updated
|
||||
* \return Success (true), Failure (false)
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean sendObjectRequest(UAVObject obj, boolean allInstances) throws IOException {
|
||||
// QMutexLocker locker(mutex);
|
||||
@ -213,7 +240,7 @@ public class UAVTalk extends Observable {
|
||||
* Object to send \param[in] acked Selects if an ack is required \param[in]
|
||||
* allInstances If set true then all instances will be updated \return
|
||||
* Success (true), Failure (false)
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized boolean sendObject(UAVObject obj, boolean acked,
|
||||
boolean allInstances) throws IOException {
|
||||
@ -237,7 +264,7 @@ public class UAVTalk extends Observable {
|
||||
* request object update TYPE_OBJ_ACK: send object with an ack \param[in]
|
||||
* allInstances If set true then all instances will be updated \return
|
||||
* Success (true), Failure (false)
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean objectTransaction(UAVObject obj, int type,
|
||||
boolean allInstances) throws IOException {
|
||||
@ -260,7 +287,7 @@ public class UAVTalk extends Observable {
|
||||
/**
|
||||
* Process an byte from the telemetry stream. \param[in] rxbyte Received
|
||||
* byte \return Success (true), Failure (false)
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized boolean processInputByte(int rxbyte) throws IOException {
|
||||
assert (objMngr != null);
|
||||
@ -341,7 +368,7 @@ public class UAVTalk extends Observable {
|
||||
// Search for object, if not found reset state machine
|
||||
rxObjId = rxTmpBuffer.getInt(0);
|
||||
// Because java treats ints as only signed we need to do this manually
|
||||
if (rxObjId < 0)
|
||||
if (rxObjId < 0)
|
||||
rxObjId = 0x100000000l + rxObjId;
|
||||
{
|
||||
UAVObject rxObj = objMngr.getObject(rxObjId);
|
||||
@ -475,11 +502,11 @@ public class UAVTalk extends Observable {
|
||||
* received object \param[in] instId The instance ID of UAVOBJ_ALL_INSTANCES
|
||||
* for all instances. \param[in] data Data buffer \param[in] length Buffer
|
||||
* length \return Success (true), Failure (false)
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean receiveObject(int type, long objId, long instId,
|
||||
ByteBuffer data) throws IOException {
|
||||
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Received object ID: " + objId);
|
||||
assert (objMngr != null);
|
||||
|
||||
@ -622,12 +649,12 @@ public class UAVTalk extends Observable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an object through the telemetry link.
|
||||
* Send an object through the telemetry link.
|
||||
* @param[in] obj Object to send
|
||||
* @param[in] type Transaction type
|
||||
* @param[in] allInstances True is all instances of the object are to be sent
|
||||
* @param[in] type Transaction type
|
||||
* @param[in] allInstances True is all instances of the object are to be sent
|
||||
* @return Success (true), Failure (false)
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized boolean transmitObject(UAVObject obj, int type, boolean allInstances) throws IOException {
|
||||
// If all instances are requested on a single instance object it is an
|
||||
@ -665,7 +692,7 @@ public class UAVTalk extends Observable {
|
||||
|
||||
/**
|
||||
* Send an object through the telemetry link.
|
||||
* @throws IOException
|
||||
* @throws IOException
|
||||
* @param[in] obj Object handle to send
|
||||
* @param[in] type Transaction type \return Success (true), Failure (false)
|
||||
*/
|
||||
@ -738,11 +765,11 @@ public class UAVTalk extends Observable {
|
||||
|
||||
/**
|
||||
* Update the crc value with new data.
|
||||
*
|
||||
*
|
||||
* Generated by pycrc v0.7.5, http://www.tty1.net/pycrc/ using the
|
||||
* configuration: Width = 8 Poly = 0x07 XorIn = 0x00 ReflectIn = False
|
||||
* XorOut = 0x00 ReflectOut = False Algorithm = table-driven
|
||||
*
|
||||
*
|
||||
* \param crc The current crc value. \param data Pointer to a buffer of \a
|
||||
* data_len bytes. \param length Number of bytes in the \a data buffer.
|
||||
* \return The updated crc value.
|
||||
@ -753,7 +780,7 @@ public class UAVTalk extends Observable {
|
||||
|
||||
int updateCRC(int crc, byte[] data, int length) {
|
||||
for (int i = 0; i < length; i++)
|
||||
crc = updateCRC(crc, (int) data[i]);
|
||||
crc = updateCRC(crc, data[i]);
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,210 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file uavobjecttemplate.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @brief Template for an uavobject in java
|
||||
* This is a autogenerated file!! Do not modify and expect a result.
|
||||
* Settings for the @ref GuidanceModule
|
||||
*
|
||||
* @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.uavtalk.uavobjects;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
import org.openpilot.uavtalk.UAVDataObject;
|
||||
import org.openpilot.uavtalk.UAVObjectField;
|
||||
|
||||
/**
|
||||
Settings for the @ref GuidanceModule
|
||||
|
||||
generated from guidancesettings.xml
|
||||
**/
|
||||
public class GuidanceSettings extends UAVDataObject {
|
||||
|
||||
public GuidanceSettings() {
|
||||
super(OBJID, ISSINGLEINST, ISSETTINGS, NAME);
|
||||
|
||||
List<UAVObjectField> fields = new ArrayList<UAVObjectField>();
|
||||
|
||||
|
||||
List<String> HorizontalPosPIElemNames = new ArrayList<String>();
|
||||
HorizontalPosPIElemNames.add("Kp");
|
||||
HorizontalPosPIElemNames.add("Ki");
|
||||
HorizontalPosPIElemNames.add("ILimit");
|
||||
fields.add( new UAVObjectField("HorizontalPosPI", "(m/s)/m", UAVObjectField.FieldType.FLOAT32, HorizontalPosPIElemNames, null) );
|
||||
|
||||
List<String> HorizontalVelPIDElemNames = new ArrayList<String>();
|
||||
HorizontalVelPIDElemNames.add("Kp");
|
||||
HorizontalVelPIDElemNames.add("Ki");
|
||||
HorizontalVelPIDElemNames.add("Kd");
|
||||
HorizontalVelPIDElemNames.add("ILimit");
|
||||
fields.add( new UAVObjectField("HorizontalVelPID", "deg/(m/s)", UAVObjectField.FieldType.FLOAT32, HorizontalVelPIDElemNames, null) );
|
||||
|
||||
List<String> VerticalPosPIElemNames = new ArrayList<String>();
|
||||
VerticalPosPIElemNames.add("Kp");
|
||||
VerticalPosPIElemNames.add("Ki");
|
||||
VerticalPosPIElemNames.add("ILimit");
|
||||
fields.add( new UAVObjectField("VerticalPosPI", "", UAVObjectField.FieldType.FLOAT32, VerticalPosPIElemNames, null) );
|
||||
|
||||
List<String> VerticalVelPIDElemNames = new ArrayList<String>();
|
||||
VerticalVelPIDElemNames.add("Kp");
|
||||
VerticalVelPIDElemNames.add("Ki");
|
||||
VerticalVelPIDElemNames.add("Kd");
|
||||
VerticalVelPIDElemNames.add("ILimit");
|
||||
fields.add( new UAVObjectField("VerticalVelPID", "", UAVObjectField.FieldType.FLOAT32, VerticalVelPIDElemNames, null) );
|
||||
|
||||
List<String> MaxRollPitchElemNames = new ArrayList<String>();
|
||||
MaxRollPitchElemNames.add("0");
|
||||
fields.add( new UAVObjectField("MaxRollPitch", "deg", UAVObjectField.FieldType.FLOAT32, MaxRollPitchElemNames, null) );
|
||||
|
||||
List<String> UpdatePeriodElemNames = new ArrayList<String>();
|
||||
UpdatePeriodElemNames.add("0");
|
||||
fields.add( new UAVObjectField("UpdatePeriod", "", UAVObjectField.FieldType.INT32, UpdatePeriodElemNames, null) );
|
||||
|
||||
List<String> HorizontalVelMaxElemNames = new ArrayList<String>();
|
||||
HorizontalVelMaxElemNames.add("0");
|
||||
fields.add( new UAVObjectField("HorizontalVelMax", "m/s", UAVObjectField.FieldType.UINT16, HorizontalVelMaxElemNames, null) );
|
||||
|
||||
List<String> VerticalVelMaxElemNames = new ArrayList<String>();
|
||||
VerticalVelMaxElemNames.add("0");
|
||||
fields.add( new UAVObjectField("VerticalVelMax", "m/s", UAVObjectField.FieldType.UINT16, VerticalVelMaxElemNames, null) );
|
||||
|
||||
List<String> GuidanceModeElemNames = new ArrayList<String>();
|
||||
GuidanceModeElemNames.add("0");
|
||||
List<String> GuidanceModeEnumOptions = new ArrayList<String>();
|
||||
GuidanceModeEnumOptions.add("DUAL_LOOP");
|
||||
GuidanceModeEnumOptions.add("VELOCITY_CONTROL");
|
||||
fields.add( new UAVObjectField("GuidanceMode", "", UAVObjectField.FieldType.ENUM, GuidanceModeElemNames, GuidanceModeEnumOptions) );
|
||||
|
||||
List<String> ThrottleControlElemNames = new ArrayList<String>();
|
||||
ThrottleControlElemNames.add("0");
|
||||
List<String> ThrottleControlEnumOptions = new ArrayList<String>();
|
||||
ThrottleControlEnumOptions.add("FALSE");
|
||||
ThrottleControlEnumOptions.add("TRUE");
|
||||
fields.add( new UAVObjectField("ThrottleControl", "", UAVObjectField.FieldType.ENUM, ThrottleControlElemNames, ThrottleControlEnumOptions) );
|
||||
|
||||
|
||||
// Compute the number of bytes for this object
|
||||
int numBytes = 0;
|
||||
ListIterator<UAVObjectField> li = fields.listIterator();
|
||||
while(li.hasNext()) {
|
||||
numBytes += li.next().getNumBytes();
|
||||
}
|
||||
NUMBYTES = numBytes;
|
||||
|
||||
// Initialize object
|
||||
initializeFields(fields, ByteBuffer.allocate(NUMBYTES), NUMBYTES);
|
||||
// Set the default field values
|
||||
setDefaultFieldValues();
|
||||
// Set the object description
|
||||
setDescription(DESCRIPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Metadata object filled with default values for this object
|
||||
* @return Metadata object with default values
|
||||
*/
|
||||
public Metadata getDefaultMetadata() {
|
||||
UAVObject.Metadata metadata = new UAVObject.Metadata();
|
||||
metadata.flags =
|
||||
UAVObject.Metadata.AccessModeNum(UAVObject.AccessMode.ACCESS_READWRITE) << UAVOBJ_ACCESS_SHIFT |
|
||||
UAVObject.Metadata.AccessModeNum(UAVObject.AccessMode.ACCESS_READWRITE) << UAVOBJ_GCS_ACCESS_SHIFT |
|
||||
1 << UAVOBJ_TELEMETRY_ACKED_SHIFT |
|
||||
1 << UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT |
|
||||
UAVObject.Metadata.UpdateModeNum(UAVObject.UpdateMode.UPDATEMODE_ONCHANGE) << UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT |
|
||||
UAVObject.Metadata.UpdateModeNum(UAVObject.UpdateMode.UPDATEMODE_ONCHANGE) << UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT;
|
||||
metadata.flightTelemetryUpdatePeriod = 0;
|
||||
metadata.gcsTelemetryUpdatePeriod = 0;
|
||||
metadata.loggingUpdatePeriod = 0;
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize object fields with the default values.
|
||||
* If a default value is not specified the object fields
|
||||
* will be initialized to zero.
|
||||
*/
|
||||
public void setDefaultFieldValues()
|
||||
{
|
||||
getField("HorizontalPosPI").setValue(0.1,0);
|
||||
getField("HorizontalPosPI").setValue(0.001,1);
|
||||
getField("HorizontalPosPI").setValue(300,2);
|
||||
getField("HorizontalVelPID").setValue(0.05,0);
|
||||
getField("HorizontalVelPID").setValue(0.002,1);
|
||||
getField("HorizontalVelPID").setValue(0,2);
|
||||
getField("HorizontalVelPID").setValue(1000,3);
|
||||
getField("VerticalPosPI").setValue(0.1,0);
|
||||
getField("VerticalPosPI").setValue(0.001,1);
|
||||
getField("VerticalPosPI").setValue(200,2);
|
||||
getField("VerticalVelPID").setValue(0.1,0);
|
||||
getField("VerticalVelPID").setValue(0,1);
|
||||
getField("VerticalVelPID").setValue(0,2);
|
||||
getField("VerticalVelPID").setValue(0,3);
|
||||
getField("MaxRollPitch").setValue(10);
|
||||
getField("UpdatePeriod").setValue(100);
|
||||
getField("HorizontalVelMax").setValue(300);
|
||||
getField("VerticalVelMax").setValue(150);
|
||||
getField("GuidanceMode").setValue("DUAL_LOOP");
|
||||
getField("ThrottleControl").setValue("FALSE");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a clone of this object, a new instance ID must be specified.
|
||||
* Do not use this function directly to create new instances, the
|
||||
* UAVObjectManager should be used instead.
|
||||
*/
|
||||
public UAVDataObject clone(long instID) {
|
||||
// TODO: Need to get specific instance to clone
|
||||
try {
|
||||
GuidanceSettings obj = new GuidanceSettings();
|
||||
obj.initialize(instID, this.getMetaObject());
|
||||
return obj;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to retrieve an instance of the object.
|
||||
*/
|
||||
public GuidanceSettings GetInstance(UAVObjectManager objMngr, long instID)
|
||||
{
|
||||
return (GuidanceSettings)(objMngr.getObject(GuidanceSettings.OBJID, instID));
|
||||
}
|
||||
|
||||
// Constants
|
||||
protected static final long OBJID = 0x6EA79FB4l;
|
||||
protected static final String NAME = "GuidanceSettings";
|
||||
protected static String DESCRIPTION = "Settings for the @ref GuidanceModule";
|
||||
protected static final boolean ISSINGLEINST = 1 > 0;
|
||||
protected static final boolean ISSETTINGS = 1 > 0;
|
||||
protected static int NUMBYTES = 0;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file uavobjecttemplate.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @brief Template for an uavobject in java
|
||||
* This is a autogenerated file!! Do not modify and expect a result.
|
||||
* The position the craft is trying t achieve. Can come from GCS or @ref PathPlanner
|
||||
*
|
||||
* @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.uavtalk.uavobjects;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import org.openpilot.uavtalk.UAVObjectManager;
|
||||
import org.openpilot.uavtalk.UAVObject;
|
||||
import org.openpilot.uavtalk.UAVDataObject;
|
||||
import org.openpilot.uavtalk.UAVObjectField;
|
||||
|
||||
/**
|
||||
The position the craft is trying t achieve. Can come from GCS or @ref PathPlanner
|
||||
|
||||
generated from positiondesired.xml
|
||||
**/
|
||||
public class PositionDesired extends UAVDataObject {
|
||||
|
||||
public PositionDesired() {
|
||||
super(OBJID, ISSINGLEINST, ISSETTINGS, NAME);
|
||||
|
||||
List<UAVObjectField> fields = new ArrayList<UAVObjectField>();
|
||||
|
||||
|
||||
List<String> NorthElemNames = new ArrayList<String>();
|
||||
NorthElemNames.add("0");
|
||||
fields.add( new UAVObjectField("North", "m", UAVObjectField.FieldType.FLOAT32, NorthElemNames, null) );
|
||||
|
||||
List<String> EastElemNames = new ArrayList<String>();
|
||||
EastElemNames.add("0");
|
||||
fields.add( new UAVObjectField("East", "m", UAVObjectField.FieldType.FLOAT32, EastElemNames, null) );
|
||||
|
||||
List<String> DownElemNames = new ArrayList<String>();
|
||||
DownElemNames.add("0");
|
||||
fields.add( new UAVObjectField("Down", "m", UAVObjectField.FieldType.FLOAT32, DownElemNames, null) );
|
||||
|
||||
|
||||
// Compute the number of bytes for this object
|
||||
int numBytes = 0;
|
||||
ListIterator<UAVObjectField> li = fields.listIterator();
|
||||
while(li.hasNext()) {
|
||||
numBytes += li.next().getNumBytes();
|
||||
}
|
||||
NUMBYTES = numBytes;
|
||||
|
||||
// Initialize object
|
||||
initializeFields(fields, ByteBuffer.allocate(NUMBYTES), NUMBYTES);
|
||||
// Set the default field values
|
||||
setDefaultFieldValues();
|
||||
// Set the object description
|
||||
setDescription(DESCRIPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Metadata object filled with default values for this object
|
||||
* @return Metadata object with default values
|
||||
*/
|
||||
public Metadata getDefaultMetadata() {
|
||||
UAVObject.Metadata metadata = new UAVObject.Metadata();
|
||||
metadata.flags =
|
||||
UAVObject.Metadata.AccessModeNum(UAVObject.AccessMode.ACCESS_READWRITE) << UAVOBJ_ACCESS_SHIFT |
|
||||
UAVObject.Metadata.AccessModeNum(UAVObject.AccessMode.ACCESS_READWRITE) << UAVOBJ_GCS_ACCESS_SHIFT |
|
||||
0 << UAVOBJ_TELEMETRY_ACKED_SHIFT |
|
||||
0 << UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT |
|
||||
UAVObject.Metadata.UpdateModeNum(UAVObject.UpdateMode.UPDATEMODE_ONCHANGE) << UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT |
|
||||
UAVObject.Metadata.UpdateModeNum(UAVObject.UpdateMode.UPDATEMODE_MANUAL) << UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT;
|
||||
metadata.flightTelemetryUpdatePeriod = 0;
|
||||
metadata.gcsTelemetryUpdatePeriod = 0;
|
||||
metadata.loggingUpdatePeriod = 1000;
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize object fields with the default values.
|
||||
* If a default value is not specified the object fields
|
||||
* will be initialized to zero.
|
||||
*/
|
||||
public void setDefaultFieldValues()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a clone of this object, a new instance ID must be specified.
|
||||
* Do not use this function directly to create new instances, the
|
||||
* UAVObjectManager should be used instead.
|
||||
*/
|
||||
public UAVDataObject clone(long instID) {
|
||||
// TODO: Need to get specific instance to clone
|
||||
try {
|
||||
PositionDesired obj = new PositionDesired();
|
||||
obj.initialize(instID, this.getMetaObject());
|
||||
return obj;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to retrieve an instance of the object.
|
||||
*/
|
||||
public PositionDesired GetInstance(UAVObjectManager objMngr, long instID)
|
||||
{
|
||||
return (PositionDesired)(objMngr.getObject(PositionDesired.OBJID, instID));
|
||||
}
|
||||
|
||||
// Constants
|
||||
protected static final long OBJID = 0x778DBE24l;
|
||||
protected static final String NAME = "PositionDesired";
|
||||
protected static String DESCRIPTION = "The position the craft is trying t achieve. Can come from GCS or @ref PathPlanner ";
|
||||
protected static final boolean ISSINGLEINST = 1 > 0;
|
||||
protected static final boolean ISSETTINGS = 0 > 0;
|
||||
protected static int NUMBYTES = 0;
|
||||
|
||||
|
||||
}
|
4267
artwork/Android/hdpi/_pre_production/pfd.ai
Normal file
4267
artwork/Android/hdpi/_pre_production/pfd.ai
Normal file
File diff suppressed because one or more lines are too long
BIN
artwork/Android/hdpi/im_pfd_horizon.png
Normal file
BIN
artwork/Android/hdpi/im_pfd_horizon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
@ -94,8 +94,8 @@
|
||||
|
||||
/* Task stack sizes */
|
||||
#define PIOS_ACTUATOR_STACK_SIZE 1020
|
||||
#define PIOS_MANUAL_STACK_SIZE 724
|
||||
#define PIOS_SYSTEM_STACK_SIZE 460
|
||||
#define PIOS_MANUAL_STACK_SIZE 800
|
||||
#define PIOS_SYSTEM_STACK_SIZE 660
|
||||
#define PIOS_STABILIZATION_STACK_SIZE 524
|
||||
#define PIOS_TELEM_STACK_SIZE 500
|
||||
#define PIOS_EVENTDISPATCHER_STACK_SIZE 130
|
||||
|
@ -242,7 +242,7 @@ int WMM_GetMagVector(float Lat, float Lon, float AltEllipsoid, uint16_t Month, u
|
||||
{
|
||||
CoordGeodetic->lambda = Lon;
|
||||
CoordGeodetic->phi = Lat;
|
||||
CoordGeodetic->HeightAboveEllipsoid = AltEllipsoid;
|
||||
CoordGeodetic->HeightAboveEllipsoid = AltEllipsoid/1000.0; // convert to km
|
||||
|
||||
// Convert from geodeitic to Spherical Equations: 17-18, WMM Technical report
|
||||
if (WMM_GeodeticToSpherical(CoordGeodetic, CoordSpherical) < 0)
|
||||
|
@ -375,6 +375,10 @@ static int32_t updateSensorsCC3D(AccelsData * accelsData, GyrosData * gyrosData)
|
||||
if(xQueueReceive(queue, (void *) &mpu6000_data, SENSOR_PERIOD) == errQUEUE_EMPTY)
|
||||
return -1; // Error, no data
|
||||
|
||||
// Do not read raw sensor data in simulation mode
|
||||
if (GyrosReadOnly() || AccelsReadOnly())
|
||||
return 0;
|
||||
|
||||
gyros[0] = -mpu6000_data.gyro_y * PIOS_MPU6000_GetScale();
|
||||
gyros[1] = -mpu6000_data.gyro_x * PIOS_MPU6000_GetScale();
|
||||
gyros[2] = -mpu6000_data.gyro_z * PIOS_MPU6000_GetScale();
|
||||
|
@ -73,6 +73,7 @@
|
||||
static uint32_t idleCounter;
|
||||
static uint32_t idleCounterClear;
|
||||
static xTaskHandle systemTaskHandle;
|
||||
static xQueueHandle objectPersistenceQueue;
|
||||
static bool stackOverflow;
|
||||
static bool mallocFailed;
|
||||
|
||||
@ -122,6 +123,10 @@ int32_t SystemModInitialize(void)
|
||||
WatchdogStatusInitialize();
|
||||
#endif
|
||||
|
||||
objectPersistenceQueue = xQueueCreate(1, sizeof(UAVObjEvent));
|
||||
if (objectPersistenceQueue == NULL)
|
||||
return -1;
|
||||
|
||||
SystemModStart();
|
||||
|
||||
return 0;
|
||||
@ -133,8 +138,6 @@ MODULE_INITCALL(SystemModInitialize, 0)
|
||||
*/
|
||||
static void systemTask(void *parameters)
|
||||
{
|
||||
portTickType lastSysTime;
|
||||
|
||||
/* create all modules thread */
|
||||
MODULE_TASKCREATE_ALL;
|
||||
|
||||
@ -154,10 +157,9 @@ static void systemTask(void *parameters)
|
||||
// Initialize vars
|
||||
idleCounter = 0;
|
||||
idleCounterClear = 0;
|
||||
lastSysTime = xTaskGetTickCount();
|
||||
|
||||
// Listen for SettingPersistance object updates, connect a callback function
|
||||
ObjectPersistenceConnectCallback(&objectUpdatedCb);
|
||||
ObjectPersistenceConnectQueue(objectPersistenceQueue);
|
||||
|
||||
// Main system loop
|
||||
while (1) {
|
||||
@ -193,11 +195,14 @@ static void systemTask(void *parameters)
|
||||
FlightStatusData flightStatus;
|
||||
FlightStatusGet(&flightStatus);
|
||||
|
||||
// Wait until next period
|
||||
if(flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED) {
|
||||
vTaskDelayUntil(&lastSysTime, SYSTEM_UPDATE_PERIOD_MS / portTICK_RATE_MS / (LED_BLINK_RATE_HZ * 2) );
|
||||
} else {
|
||||
vTaskDelayUntil(&lastSysTime, SYSTEM_UPDATE_PERIOD_MS / portTICK_RATE_MS);
|
||||
UAVObjEvent ev;
|
||||
int delayTime = flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED ?
|
||||
SYSTEM_UPDATE_PERIOD_MS / portTICK_RATE_MS / (LED_BLINK_RATE_HZ * 2) :
|
||||
SYSTEM_UPDATE_PERIOD_MS / portTICK_RATE_MS;
|
||||
|
||||
if(xQueueReceive(objectPersistenceQueue, &ev, delayTime) == pdTRUE) {
|
||||
// If object persistence is updated call the callback
|
||||
objectUpdatedCb(&ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,7 @@ equals(copydata, 1) {
|
||||
win32:CONFIG(release, debug|release) {
|
||||
|
||||
# copy Qt DLLs and phonon4
|
||||
QT_DLLS = libgcc_s_dw2-1.dll \
|
||||
mingwm10.dll \
|
||||
phonon4.dll \
|
||||
QT_DLLS = phonon4.dll \
|
||||
QtCore4.dll \
|
||||
QtGui4.dll \
|
||||
QtNetwork4.dll \
|
||||
@ -27,6 +25,13 @@ equals(copydata, 1) {
|
||||
data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_BINS]/$$dll\") $$targetPath(\"$$GCS_APP_PATH/$$dll\") $$addNewline()
|
||||
}
|
||||
|
||||
# copy MinGW DLLs
|
||||
MINGW_DLLS = libgcc_s_dw2-1.dll \
|
||||
mingwm10.dll
|
||||
for(dll, MINGW_DLLS) {
|
||||
data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_BINS]/../../../../../mingw/bin/$$dll\") $$targetPath(\"$$GCS_APP_PATH/$$dll\") $$addNewline()
|
||||
}
|
||||
|
||||
# copy iconengines
|
||||
QT_ICONENGINE_DLLS = qsvgicon4.dll
|
||||
data_copy.commands += -@$(MKDIR) $$targetPath(\"$$GCS_APP_PATH/iconengines\") $$addNewline()
|
||||
|
@ -158,7 +158,7 @@ namespace Utils {
|
||||
{
|
||||
double Lat = LLA[0];
|
||||
double Lon = LLA[1];
|
||||
double AltEllipsoid = LLA[2];
|
||||
double AltEllipsoid = LLA[2]/1000.0; // convert to km
|
||||
|
||||
// ***********
|
||||
// range check supplied params
|
||||
|
@ -180,7 +180,6 @@ void VehicleConfig::setMixerType(UAVDataObject* mixer, int channel, MixerTypeEle
|
||||
if (mixerType >= 0 && mixerType < mixerTypeDescriptions.count())
|
||||
{
|
||||
field->setValue(mixerTypeDescriptions[mixerType]);
|
||||
mixer->updated();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -228,7 +227,6 @@ void VehicleConfig::setMixerVectorValue(UAVDataObject* mixer, int channel, Mixer
|
||||
|
||||
if (field) {
|
||||
field->setDouble(value, elementName);
|
||||
mixer->updated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -135,6 +135,14 @@ void ConfigStabilizationWidget::processLinkedWidgets(QWidget * widget)
|
||||
{
|
||||
m_stabilization->RateRollILimit_2->setValue(m_stabilization->RatePitchILimit->value());
|
||||
}
|
||||
else if(widget== m_stabilization->RollRateKd)
|
||||
{
|
||||
m_stabilization->PitchRateKd->setValue(m_stabilization->RollRateKd->value());
|
||||
}
|
||||
else if(widget== m_stabilization->PitchRateKd)
|
||||
{
|
||||
m_stabilization->RollRateKd->setValue(m_stabilization->PitchRateKd->value());
|
||||
}
|
||||
}
|
||||
if(m_stabilization->checkBox_8->checkState()==Qt::Checked)
|
||||
{
|
||||
|
@ -1,3 +1,30 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file aerosimrc.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "aerosimrc.h"
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
@ -1,3 +1,30 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file aerosimrc.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef AEROSIMRC_H
|
||||
#define AEROSIMRC_H
|
||||
|
||||
|
@ -0,0 +1,10 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
win32 {
|
||||
SUBDIRS += plugin
|
||||
}
|
||||
|
||||
SUBDIRS += udptest
|
||||
|
||||
plugin.file = src/plugin.pro
|
||||
udptest.file = src/udptest.pro
|
@ -0,0 +1,206 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file aerosimrcdatastruct.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef AEROSIMRCDATASTRUCT_H
|
||||
#define AEROSIMRCDATASTRUCT_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
const quint8 AEROSIMRC_MAX_CHANNELS = 39;
|
||||
const quint16 DBG_BUFFER_MAX_SIZE = 4096;
|
||||
|
||||
#define MAX_DLL_USER_MENU_ITEMS 16
|
||||
#define OBSOLETE_MIT_COMMAND (1 << 0)
|
||||
#define OBSOLETE_MIT_CHECKBOX (1 << 1)
|
||||
#define OBSOLETE_MIT_SEPARATOR (1 << 7)
|
||||
|
||||
#define PACK_STRUCT __attribute__((packed))
|
||||
|
||||
struct simToPlugin
|
||||
{
|
||||
quint16 structSize;
|
||||
float simTimeStep;
|
||||
float chSimTX[AEROSIMRC_MAX_CHANNELS];
|
||||
float chSimRX[AEROSIMRC_MAX_CHANNELS];
|
||||
uchar *OSDVideoBuf;
|
||||
quint32 simMenuStatus;
|
||||
float initPosX;
|
||||
float initPosY;
|
||||
float initPosZ;
|
||||
float initHeading;
|
||||
float initPitch;
|
||||
float initRoll;
|
||||
float wpHomeX;
|
||||
float wpHomeY;
|
||||
float wpHomeLat;
|
||||
float wpHomeLong;
|
||||
const char *wpHomeDesc; // (m, deg, string)
|
||||
float wpAX;
|
||||
float wpAY;
|
||||
float wpALat;
|
||||
float wpALong;
|
||||
const char *wpADesc; // (m, deg, string)
|
||||
float wpBX;
|
||||
float wpBY;
|
||||
float wpBLat;
|
||||
float wpBLong;
|
||||
const char *wpBDesc; // (m, deg, string)
|
||||
float wpCX;
|
||||
float wpCY;
|
||||
float wpCLat;
|
||||
float wpCLong;
|
||||
const char *wpCDesc; // (m, deg, string)
|
||||
float wpDX;
|
||||
float wpDY;
|
||||
float wpDLat;
|
||||
float wpDLong;
|
||||
const char *wpDDesc; // (m, deg, string)
|
||||
float posX;
|
||||
float posY;
|
||||
float posZ;
|
||||
float velX;
|
||||
float velY;
|
||||
float velZ;
|
||||
float angVelX;
|
||||
float angVelY;
|
||||
float angVelZ;
|
||||
float accelX;
|
||||
float accelY;
|
||||
float accelZ;
|
||||
qreal latitude;
|
||||
qreal longitude;
|
||||
float AGL;
|
||||
float heading;
|
||||
float pitch;
|
||||
float roll;
|
||||
float windVelX;
|
||||
float windVelY;
|
||||
float windVelZ;
|
||||
float eng1RPM;
|
||||
float eng2RPM;
|
||||
float eng3RPM;
|
||||
float eng4RPM;
|
||||
float voltage; // V
|
||||
float current; // A
|
||||
float consumedCharge; // Ah
|
||||
float capacity; // Ah
|
||||
float fuelConsumed; // l
|
||||
float fuelTankCapacity; // l
|
||||
// ver 3.83
|
||||
qint16 screenW;
|
||||
qint16 screenH;
|
||||
// Model Orientation Matrix (X=Right, Y=Front, Z=Up)
|
||||
float axisXx;
|
||||
float axisXy;
|
||||
float axisXz;
|
||||
float axisYx;
|
||||
float axisYy;
|
||||
float axisYz;
|
||||
float axisZx;
|
||||
float axisZy;
|
||||
float axisZz;
|
||||
// Model data in body frame coordinates (X=Right, Y=Front, Z=Up)
|
||||
float velXm; // m/s Model velocity in body coordinates
|
||||
float velYm;
|
||||
float velZm;
|
||||
float angVelXm; // rad/s Model angular velocity in body coordinates
|
||||
float angVelYm;
|
||||
float angVelZm;
|
||||
float accelXm; // m/s/s Model acceleration in body coordinates
|
||||
float accelYm;
|
||||
float accelZm;
|
||||
// ver 3.90
|
||||
quint32 OSDVideoBufSize;
|
||||
} PACK_STRUCT ; // normal - 592, packed - 582 OK (3.81)
|
||||
// normal - ???, packed - 658 OK (3.83)
|
||||
// normal - ???, packed - 662 OK (3.90)
|
||||
|
||||
struct pluginToSim
|
||||
{
|
||||
quint16 structSize;
|
||||
const char *dbgInfoText;
|
||||
uchar chOverTX[AEROSIMRC_MAX_CHANNELS];
|
||||
float chNewTX[AEROSIMRC_MAX_CHANNELS];
|
||||
uchar chOverRX[AEROSIMRC_MAX_CHANNELS];
|
||||
float chNewRX[AEROSIMRC_MAX_CHANNELS];
|
||||
float newPosX; // m
|
||||
float newPosY;
|
||||
float newPosZ;
|
||||
float newVelX; // m/s
|
||||
float newVelY;
|
||||
float newVelZ;
|
||||
float newAngVelX; // rad/s
|
||||
float newAngVelY;
|
||||
float newAngVelZ;
|
||||
float newHeading; // rad
|
||||
float newPitch;
|
||||
float newRoll;
|
||||
quint32 modelOverrideFlags;
|
||||
quint32 newMenuStatus;
|
||||
quint8 isOSDShow;
|
||||
quint8 isOSDChanged;
|
||||
quint16 OSDWindow_DX;
|
||||
quint16 OSDWindow_DY;
|
||||
float OSDScale;
|
||||
float newWindVelX;
|
||||
float newWindVelY;
|
||||
float newWindVelZ;
|
||||
float newEng1RPM;
|
||||
float newEng2RPM;
|
||||
float newEng3RPM;
|
||||
float newEng4RPM;
|
||||
float newVoltage;
|
||||
float newCurrent;
|
||||
float newConsumedCharge;
|
||||
float newFuelConsumed;
|
||||
quint8 modelCrashInhibit;
|
||||
// ver 3.83
|
||||
qint16 newScreenW; // Simulator window position and size on screen
|
||||
qint16 newScreenH;
|
||||
qint16 newScreenX;
|
||||
qint16 newScreenY;
|
||||
} PACK_STRUCT ; // normal 516, packed 507 OK (3.81)
|
||||
// normal ???, packed 515 OK (3.83 & 3.90)
|
||||
|
||||
struct TPluginMenuItem
|
||||
{
|
||||
quint32 OBSOLETE_eType;
|
||||
char *OBSOLETE_strName;
|
||||
} PACK_STRUCT ;
|
||||
|
||||
struct pluginInit
|
||||
{
|
||||
quint32 nStructSize;
|
||||
char *OBSOLETE_strMenuTitle;
|
||||
TPluginMenuItem OBSOLETE_atMenuItem[MAX_DLL_USER_MENU_ITEMS];
|
||||
const char *strPluginFolder;
|
||||
const char *strOutputFolder;
|
||||
} PACK_STRUCT ; // normal - 144, packed - 144 OK (3.81 & 3.83 & 3.90)
|
||||
|
||||
#undef PACK_STRUCT
|
||||
|
||||
#endif // AEROSIMRCDATASTRUCT_H
|
102
ground/openpilotgcs/src/plugins/hitlv2/aerosimrc/src/enums.h
Normal file
102
ground/openpilotgcs/src/plugins/hitlv2/aerosimrc/src/enums.h
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file enums.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef ENUMS_H
|
||||
#define ENUMS_H
|
||||
|
||||
// Custom Menu Item masks
|
||||
enum MenuMasks {
|
||||
MenuEnable = (1 << 0),
|
||||
MenuTx = (1 << 1),
|
||||
MenuRx = (1 << 2),
|
||||
MenuScreen = (1 << 3),
|
||||
MenuNextWpt = (1 << 4),
|
||||
MenuCmdReset = (1 << 5),
|
||||
MenuLedBlue = (1 << 6),
|
||||
MenuLedGreen = (1 << 7),
|
||||
MenuFMode1 = (1 << 8),
|
||||
MenuFMode2 = (1 << 9),
|
||||
MenuFMode3 = (1 << 10)
|
||||
};
|
||||
|
||||
enum EOverrideFlags
|
||||
{
|
||||
OVR_POS = (1 << 0),
|
||||
OVR_VEL = (1 << 1),
|
||||
OVR_ANG_VEL = (1 << 2),
|
||||
OVR_HPR = (1 << 3), // Override Heading, Pitch and Roll
|
||||
OVR_WIND_VEL = (1 << 4), // Override Wind velocity at model
|
||||
OVR_ENGINE_RPM = (1 << 5), // Override RPM of all Engines or Motors
|
||||
OVR_BAT_VOLT = (1 << 6), // Override motor Battery Voltage
|
||||
OVR_BAT_AMP = (1 << 7), // Override motor Battery current
|
||||
OVR_BAT_AH_CONSUMED = (1 << 8), // Override motor Battery AmpsHour consumed
|
||||
OVR_FUEL_CONSUMED = (1 << 9) // Override Fuel consumed (gas & jet engines)
|
||||
};
|
||||
|
||||
enum Channels {
|
||||
Ch1Aileron,
|
||||
Ch2Elevator,
|
||||
Ch3Throttle,
|
||||
Ch4Rudder,
|
||||
Ch5,
|
||||
Ch6,
|
||||
Ch7,
|
||||
Ch8,
|
||||
Ch9,
|
||||
Ch10Retracts,
|
||||
Ch11Flaps,
|
||||
Ch12FPVCamPan,
|
||||
Ch13FPVCamTilt,
|
||||
Ch14Brakes,
|
||||
Ch15Spoilers,
|
||||
Ch16Smoke,
|
||||
Ch17Fire,
|
||||
Ch18FlightMode,
|
||||
Ch19ALTHold,
|
||||
Ch20FPVTiltHold,
|
||||
Ch21ResetModel,
|
||||
Ch22MouseTX,
|
||||
Ch23Plugin1,
|
||||
Ch24Plugin2,
|
||||
Ch25ThrottleHold,
|
||||
Ch26CareFree,
|
||||
Ch27FPVCamRoll,
|
||||
Ch28LMotorDual,
|
||||
Ch29RMotorDual,
|
||||
Ch30Mix,
|
||||
Ch31Mix,
|
||||
Ch32Mix,
|
||||
Ch33Mix,
|
||||
Ch34Mix,
|
||||
Ch35Mix,
|
||||
Ch36Mix,
|
||||
Ch37Mix,
|
||||
Ch38Mix,
|
||||
Ch39Mix
|
||||
};
|
||||
|
||||
#endif // ENUMS_H
|
394
ground/openpilotgcs/src/plugins/hitlv2/aerosimrc/src/plugin.cpp
Normal file
394
ground/openpilotgcs/src/plugins/hitlv2/aerosimrc/src/plugin.cpp
Normal file
@ -0,0 +1,394 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file plugin.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "udpconnect.h"
|
||||
#include "qdebughandler.h"
|
||||
#include "enums.h"
|
||||
#include "settings.h"
|
||||
|
||||
bool isFirstRun = true;
|
||||
QString debugInfo(DBG_BUFFER_MAX_SIZE, ' ');
|
||||
QString pluginFolder(MAX_PATH, ' ');
|
||||
QString outputFolder(MAX_PATH, ' ');
|
||||
|
||||
QList<quint16> videoModes;
|
||||
QTime ledTimer;
|
||||
|
||||
UdpSender *sndr;
|
||||
UdpReceiver *rcvr;
|
||||
|
||||
const float RAD2DEG = (float)(180.0 / M_PI);
|
||||
const float DEG2RAD = (float)(M_PI / 180.0);
|
||||
|
||||
//extern "C" int __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
extern "C" int __stdcall DllMain(void*, quint32 fdwReason, void*)
|
||||
{
|
||||
switch (fdwReason) {
|
||||
case 0:
|
||||
// qDebug() << hinstDLL << "DLL_PROCESS_DETACH " << lpvReserved;
|
||||
// free resources here
|
||||
rcvr->stop();
|
||||
rcvr->wait(500);
|
||||
delete rcvr;
|
||||
delete sndr;
|
||||
qDebug("------");
|
||||
break;
|
||||
case 1:
|
||||
// qDebug() << hinstDLL << " DLL_PROCESS_ATTACH " << lpvReserved;
|
||||
break;
|
||||
case 2:
|
||||
// qDebug() << hinstDLL << "DLL_THREAD_ATTACH " << lpvReserved;
|
||||
break;
|
||||
case 3:
|
||||
// qDebug() << hinstDLL << "DLL_THREAD_DETACH " << lpvReserved;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SIM_DLL_EXPORT void AeroSIMRC_Plugin_ReportStructSizes(quint32 *sizeSimToPlugin,
|
||||
quint32 *sizePluginToSim,
|
||||
quint32 *sizePluginInit)
|
||||
{
|
||||
// debug redirection
|
||||
qInstallMsgHandler(myQDebugHandler);
|
||||
|
||||
qDebug() << "AeroSIMRC_Plugin_ReportStructSizes";
|
||||
*sizeSimToPlugin = sizeof(simToPlugin);
|
||||
*sizePluginToSim = sizeof(pluginToSim);
|
||||
*sizePluginInit = sizeof(pluginInit);
|
||||
qDebug() << "sizeSimToPlugin = " << *sizeSimToPlugin;
|
||||
qDebug() << "sizePluginToSim = " << *sizePluginToSim;
|
||||
qDebug() << "sizePluginInit = " << *sizePluginInit;
|
||||
}
|
||||
|
||||
SIM_DLL_EXPORT void AeroSIMRC_Plugin_Init(pluginInit *p)
|
||||
{
|
||||
qDebug() << "AeroSIMRC_Plugin_Init begin";
|
||||
|
||||
pluginFolder = p->strPluginFolder;
|
||||
outputFolder = p->strOutputFolder;
|
||||
|
||||
ledTimer.restart();
|
||||
|
||||
Settings *ini = new Settings(pluginFolder);
|
||||
ini->read();
|
||||
|
||||
videoModes = ini->getVideoModes();
|
||||
|
||||
sndr = new UdpSender(ini->getOutputMap(), ini->isFromTX());
|
||||
sndr->init(ini->remoteHost(), ini->remotePort());
|
||||
|
||||
rcvr = new UdpReceiver(ini->getInputMap(), ini->isToRX());
|
||||
rcvr->init(ini->localHost(), ini->localPort());
|
||||
|
||||
// run thread
|
||||
rcvr->start();
|
||||
|
||||
delete ini;
|
||||
|
||||
qDebug() << "AeroSIMRC_Plugin_Init done";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Run_Command_Reset(/*const simToPlugin *stp,
|
||||
pluginToSim *pts*/)
|
||||
{
|
||||
// Print some debug info, although it will only be seen during one frame
|
||||
debugInfo.append("\nRESET");
|
||||
}
|
||||
|
||||
void Run_Command_WindowSizeAndPos(const simToPlugin *stp,
|
||||
pluginToSim *pts)
|
||||
{
|
||||
static quint8 snSequence = 0;
|
||||
quint8 idx = snSequence * 4;
|
||||
|
||||
if (snSequence >= videoModes.at(0)) { // set fullscreen
|
||||
pts->newScreenX = 0;
|
||||
pts->newScreenY = 0;
|
||||
pts->newScreenW = stp->screenW;
|
||||
pts->newScreenH = stp->screenH;
|
||||
snSequence = 0;
|
||||
} else { // set video mode from config
|
||||
pts->newScreenX = videoModes.at(idx + 1);
|
||||
pts->newScreenY = videoModes.at(idx + 2);
|
||||
pts->newScreenW = videoModes.at(idx + 3);
|
||||
pts->newScreenH = videoModes.at(idx + 4);
|
||||
snSequence++;
|
||||
}
|
||||
}
|
||||
|
||||
void Run_Command_MoveToNextWaypoint(const simToPlugin *stp,
|
||||
pluginToSim *pts)
|
||||
{
|
||||
static quint8 snSequence = 0;
|
||||
|
||||
switch(snSequence) {
|
||||
case 0:
|
||||
pts->newPosX = stp->wpAX;
|
||||
pts->newPosY = stp->wpAY;
|
||||
pts->newPosZ = 100.0;
|
||||
break;
|
||||
case 1:
|
||||
pts->newPosX = stp->wpBX;
|
||||
pts->newPosY = stp->wpBY;
|
||||
pts->newPosZ = 100.0;
|
||||
break;
|
||||
case 2:
|
||||
pts->newPosX = stp->wpCX;
|
||||
pts->newPosY = stp->wpCY;
|
||||
pts->newPosZ = 100.0;
|
||||
break;
|
||||
case 3:
|
||||
pts->newPosX = stp->wpDX;
|
||||
pts->newPosY = stp->wpDY;
|
||||
pts->newPosZ = 100.0;
|
||||
break;
|
||||
case 4:
|
||||
pts->newPosX = stp->wpHomeX;
|
||||
pts->newPosY = stp->wpHomeY;
|
||||
pts->newPosZ = 100.0;
|
||||
break;
|
||||
default:
|
||||
qFatal("Run_Command_MoveToNextWaypoint switch error");
|
||||
}
|
||||
pts->modelOverrideFlags = 0;
|
||||
pts->modelOverrideFlags |= OVR_POS;
|
||||
|
||||
snSequence++;
|
||||
if(snSequence > 4)
|
||||
snSequence = 0;
|
||||
}
|
||||
|
||||
void Run_BlinkLEDs(const simToPlugin *stp,
|
||||
pluginToSim *pts)
|
||||
{
|
||||
if ((stp->simMenuStatus & MenuEnable) != 0) {
|
||||
pts->newMenuStatus |= MenuLedGreen;
|
||||
int timeout;
|
||||
quint8 armed;
|
||||
quint8 mode;
|
||||
rcvr->getFlighStatus(armed, mode);
|
||||
debugInfo.append(QString("armed: %1, mode: %2\n").arg(armed).arg(mode));
|
||||
|
||||
if (armed == 0) // disarm
|
||||
timeout = 1000;
|
||||
else if (armed == 1) // arming
|
||||
timeout = 40;
|
||||
else if (armed == 2) // armed
|
||||
timeout = 100;
|
||||
else // unknown
|
||||
timeout = 2000;
|
||||
if (ledTimer.elapsed() > timeout) {
|
||||
ledTimer.restart();
|
||||
pts->newMenuStatus ^= MenuLedBlue;
|
||||
}
|
||||
|
||||
if (mode == 6) {
|
||||
pts->newMenuStatus |= MenuFMode3;
|
||||
pts->newMenuStatus |= MenuFMode2;
|
||||
pts->newMenuStatus |= MenuFMode1;
|
||||
} else if (mode == 5) {
|
||||
pts->newMenuStatus |= MenuFMode3;
|
||||
pts->newMenuStatus |= MenuFMode2;
|
||||
pts->newMenuStatus &= ~MenuFMode1;
|
||||
} else if (mode == 4) {
|
||||
pts->newMenuStatus |= MenuFMode3;
|
||||
pts->newMenuStatus &= ~MenuFMode2;
|
||||
pts->newMenuStatus |= MenuFMode1;
|
||||
} else if (mode == 3) {
|
||||
pts->newMenuStatus |= MenuFMode3;
|
||||
pts->newMenuStatus &= ~MenuFMode2;
|
||||
pts->newMenuStatus &= ~MenuFMode1;
|
||||
} else if (mode == 2) {
|
||||
pts->newMenuStatus &= ~MenuFMode3;
|
||||
pts->newMenuStatus |= MenuFMode2;
|
||||
pts->newMenuStatus &= ~MenuFMode1;
|
||||
} else if (mode == 1) {
|
||||
pts->newMenuStatus &= ~MenuFMode3;
|
||||
pts->newMenuStatus &= ~MenuFMode2;
|
||||
pts->newMenuStatus |= MenuFMode1;
|
||||
} else /*(mode == 0)*/ {
|
||||
pts->newMenuStatus &= ~MenuFMode3;
|
||||
pts->newMenuStatus &= ~MenuFMode2;
|
||||
pts->newMenuStatus &= ~MenuFMode1;
|
||||
}
|
||||
} else {
|
||||
pts->newMenuStatus = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void InfoText(const simToPlugin *stp,
|
||||
pluginToSim *pts)
|
||||
{
|
||||
debugInfo.append(
|
||||
QString(
|
||||
"Plugin Folder = %1\n"
|
||||
"Output Folder = %2\n"
|
||||
"nStructSize = %3 "
|
||||
"fIntegrationTimeStep = %4\n"
|
||||
"\n"
|
||||
"Aileron TX = %5 RX = %6 RCMD TX = %7 RX = %8\n"
|
||||
"Elevator TX = %9 RX = %10 RCMD TX = %11 RX = %12\n"
|
||||
"Throttle TX = %13 RX = %14 RCMD TX = %15 RX = %16\n"
|
||||
"Rudder TX = %17 RX = %18 RCMD TX = %19 RX = %20\n"
|
||||
"Channel5 TX = %21 RX = %22 RCMD TX = %23 RX = %24\n"
|
||||
"Channel6 TX = %25 RX = %26 RCMD TX = %27 RX = %28\n"
|
||||
"Channel7 TX = %29 RX = %30 RCMD TX = %31 RX = %32\n"
|
||||
"PluginCh1 TX = %33 RX = %34 RCMD TX = %35 RX = %36\n"
|
||||
"PluginCh2 TX = %37 RX = %38 RCMD TX = %39 RX = %40\n"
|
||||
"FPVCamPan TX = %41 RX = %42 RCMD TX = %43 RX = %44\n"
|
||||
"FPVCamTil TX = %45 RX = %46 RCMD TX = %47 RX = %48\n"
|
||||
"\n"
|
||||
"MenuItems = %49\n"
|
||||
// Model data
|
||||
"\n"
|
||||
"fPosX,Y,Z = (%50, %51, %52)\n"
|
||||
"fVelX,Y,Z = (%53, %54, %55)\n"
|
||||
"fAngVelX,Y,Z = (%56, %57, %58)\n"
|
||||
"fAccelX,Y,Z = (%59, %60, %61)\n"
|
||||
"\n"
|
||||
"Lat, Long = %62, %63\n"
|
||||
"fHeightAboveTerrain = %64\n"
|
||||
"\n"
|
||||
"fHeading = %65 fPitch = %66 fRoll = %67\n"
|
||||
)
|
||||
.arg(pluginFolder)
|
||||
.arg(outputFolder)
|
||||
.arg(stp->structSize)
|
||||
.arg(1.0 / stp->simTimeStep, 4, 'f', 1)
|
||||
.arg(stp->chSimTX[Ch1Aileron], 5, 'f', 2)
|
||||
.arg(stp->chSimRX[Ch1Aileron], 5, 'f', 2)
|
||||
.arg(pts->chNewTX[Ch1Aileron], 5, 'f', 2)
|
||||
.arg(pts->chNewRX[Ch1Aileron], 5, 'f', 2)
|
||||
.arg(stp->chSimTX[Ch2Elevator], 5, 'f', 2)
|
||||
.arg(stp->chSimRX[Ch2Elevator], 5, 'f', 2)
|
||||
.arg(pts->chNewTX[Ch2Elevator], 5, 'f', 2)
|
||||
.arg(pts->chNewRX[Ch2Elevator], 5, 'f', 2)
|
||||
.arg(stp->chSimTX[Ch3Throttle], 5, 'f', 2)
|
||||
.arg(stp->chSimRX[Ch3Throttle], 5, 'f', 2)
|
||||
.arg(pts->chNewTX[Ch3Throttle], 5, 'f', 2)
|
||||
.arg(pts->chNewRX[Ch3Throttle], 5, 'f', 2)
|
||||
.arg(stp->chSimTX[Ch4Rudder], 5, 'f', 2)
|
||||
.arg(stp->chSimRX[Ch4Rudder], 5, 'f', 2)
|
||||
.arg(pts->chNewTX[Ch4Rudder], 5, 'f', 2)
|
||||
.arg(pts->chNewRX[Ch4Rudder], 5, 'f', 2)
|
||||
.arg(stp->chSimTX[Ch5], 5, 'f', 2)
|
||||
.arg(stp->chSimRX[Ch5], 5, 'f', 2)
|
||||
.arg(pts->chNewTX[Ch5], 5, 'f', 2)
|
||||
.arg(pts->chNewRX[Ch5], 5, 'f', 2)
|
||||
.arg(stp->chSimTX[Ch6], 5, 'f', 2)
|
||||
.arg(stp->chSimRX[Ch6], 5, 'f', 2)
|
||||
.arg(pts->chNewTX[Ch6], 5, 'f', 2)
|
||||
.arg(pts->chNewRX[Ch6], 5, 'f', 2)
|
||||
.arg(stp->chSimTX[Ch7], 5, 'f', 2)
|
||||
.arg(stp->chSimRX[Ch7], 5, 'f', 2)
|
||||
.arg(pts->chNewTX[Ch7], 5, 'f', 2)
|
||||
.arg(pts->chNewRX[Ch7], 5, 'f', 2)
|
||||
.arg(stp->chSimTX[Ch23Plugin1], 5, 'f', 2)
|
||||
.arg(stp->chSimRX[Ch23Plugin1], 5, 'f', 2)
|
||||
.arg(pts->chNewTX[Ch23Plugin1], 5, 'f', 2)
|
||||
.arg(pts->chNewRX[Ch23Plugin1], 5, 'f', 2)
|
||||
.arg(stp->chSimTX[Ch24Plugin2], 5, 'f', 2)
|
||||
.arg(stp->chSimRX[Ch24Plugin2], 5, 'f', 2)
|
||||
.arg(pts->chNewTX[Ch24Plugin2], 5, 'f', 2)
|
||||
.arg(pts->chNewRX[Ch24Plugin2], 5, 'f', 2)
|
||||
.arg(stp->chSimTX[Ch12FPVCamPan], 5, 'f', 2)
|
||||
.arg(stp->chSimRX[Ch12FPVCamPan], 5, 'f', 2)
|
||||
.arg(pts->chNewTX[Ch12FPVCamPan], 5, 'f', 2)
|
||||
.arg(pts->chNewRX[Ch12FPVCamPan], 5, 'f', 2)
|
||||
.arg(stp->chSimTX[Ch13FPVCamTilt], 5, 'f', 2)
|
||||
.arg(stp->chSimRX[Ch13FPVCamTilt], 5, 'f', 2)
|
||||
.arg(pts->chNewTX[Ch13FPVCamTilt], 5, 'f', 2)
|
||||
.arg(pts->chNewRX[Ch13FPVCamTilt], 5, 'f', 2)
|
||||
.arg(stp->simMenuStatus)
|
||||
.arg(stp->posX, 5, 'f', 2)
|
||||
.arg(stp->posY, 5, 'f', 2)
|
||||
.arg(stp->posZ, 5, 'f', 2)
|
||||
.arg(stp->velX, 5, 'f', 2)
|
||||
.arg(stp->velY, 5, 'f', 2)
|
||||
.arg(stp->velZ, 5, 'f', 2)
|
||||
.arg(stp->angVelXm, 5, 'f', 2)
|
||||
.arg(stp->angVelYm, 5, 'f', 2)
|
||||
.arg(stp->angVelZm, 5, 'f', 2)
|
||||
.arg(stp->accelXm, 5, 'f', 2)
|
||||
.arg(stp->accelYm, 5, 'f', 2)
|
||||
.arg(stp->accelZm, 5, 'f', 2)
|
||||
.arg(stp->latitude, 5, 'f', 2)
|
||||
.arg(stp->longitude, 5, 'f', 2)
|
||||
.arg(stp->AGL, 5, 'f', 2)
|
||||
.arg(stp->heading*RAD2DEG, 5, 'f', 2)
|
||||
.arg(stp->pitch*RAD2DEG, 5, 'f', 2)
|
||||
.arg(stp->roll*RAD2DEG, 5, 'f', 2)
|
||||
);
|
||||
}
|
||||
|
||||
SIM_DLL_EXPORT void AeroSIMRC_Plugin_Run(const simToPlugin *stp,
|
||||
pluginToSim *pts)
|
||||
{
|
||||
debugInfo = "---\n";
|
||||
// By default do not change the Menu Items of type CheckBox
|
||||
pts->newMenuStatus = stp->simMenuStatus;
|
||||
// Extract Menu Commands from Flags
|
||||
bool isReset = (stp->simMenuStatus & MenuCmdReset) != 0;
|
||||
bool isEnable = (stp->simMenuStatus & MenuEnable) != 0;
|
||||
bool isTxON = (stp->simMenuStatus & MenuTx) != 0;
|
||||
bool isRxON = (stp->simMenuStatus & MenuRx) != 0;
|
||||
bool isScreen = (stp->simMenuStatus & MenuScreen) != 0;
|
||||
bool isNextWp = (stp->simMenuStatus & MenuNextWpt) != 0;
|
||||
// Run commands
|
||||
if (isReset) {
|
||||
Run_Command_Reset(/*stp, pts*/);
|
||||
} else if (isScreen) {
|
||||
Run_Command_WindowSizeAndPos(stp, pts);
|
||||
} else if (isNextWp) {
|
||||
Run_Command_MoveToNextWaypoint(stp, pts);
|
||||
} else {
|
||||
Run_BlinkLEDs(stp, pts);
|
||||
if (isEnable) {
|
||||
if (isTxON)
|
||||
sndr->sendDatagram(stp);
|
||||
if (isRxON)
|
||||
rcvr->setChannels(pts);
|
||||
}
|
||||
|
||||
// network lag
|
||||
debugInfo.append(QString("out: %1, inp: %2, delta: %3\n")
|
||||
.arg(sndr->pcks() - 1)
|
||||
.arg(rcvr->pcks())
|
||||
.arg(sndr->pcks() - rcvr->pcks() - 1)
|
||||
);
|
||||
}
|
||||
|
||||
// debug info is shown on the screen
|
||||
InfoText(stp, pts);
|
||||
pts->dbgInfoText = debugInfo.toAscii();
|
||||
isFirstRun = false;
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file plugin.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef PLUGIN_H
|
||||
#define PLUGIN_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QTime>
|
||||
#include <QList>
|
||||
#include "aerosimrcdatastruct.h"
|
||||
|
||||
#define SIM_DLL_EXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
SIM_DLL_EXPORT void AeroSIMRC_Plugin_ReportStructSizes(
|
||||
quint32 *sizeSimToPlugin,
|
||||
quint32 *sizePluginToSim,
|
||||
quint32 *sizePluginInit
|
||||
);
|
||||
|
||||
SIM_DLL_EXPORT void AeroSIMRC_Plugin_Init(
|
||||
pluginInit *p
|
||||
);
|
||||
|
||||
SIM_DLL_EXPORT void AeroSIMRC_Plugin_Run(
|
||||
const simToPlugin *stp,
|
||||
pluginToSim *pts
|
||||
);
|
||||
|
||||
#endif // PLUGIN_H
|
@ -0,0 +1,71 @@
|
||||
!win32 {
|
||||
error("AeroSimRC plugin is only available for win32 platform")
|
||||
}
|
||||
|
||||
include(../../../../../openpilotgcs.pri)
|
||||
|
||||
QT += network
|
||||
QT -= gui
|
||||
|
||||
TEMPLATE = lib
|
||||
TARGET = plugin_AeroSIMRC
|
||||
|
||||
RES_DIR = $${PWD}/resources
|
||||
SIM_DIR = $$GCS_BUILD_TREE/../AeroSIM-RC
|
||||
PLUGIN_DIR = $$SIM_DIR/Plugin/CopterControl
|
||||
DLLDESTDIR = $$PLUGIN_DIR
|
||||
|
||||
HEADERS = \
|
||||
aerosimrcdatastruct.h \
|
||||
enums.h \
|
||||
plugin.h \
|
||||
qdebughandler.h \
|
||||
udpconnect.h \
|
||||
settings.h
|
||||
|
||||
SOURCES = \
|
||||
qdebughandler.cpp \
|
||||
plugin.cpp \
|
||||
udpconnect.cpp \
|
||||
settings.cpp
|
||||
|
||||
# Resemble the AeroSimRC directory structure and copy plugin files and resources
|
||||
equals(copydata, 1) {
|
||||
|
||||
# Windows release only
|
||||
win32:CONFIG(release, debug|release) {
|
||||
|
||||
data_copy.commands += -@$(MKDIR) $$targetPath(\"$$PLUGIN_DIR\") $$addNewline()
|
||||
|
||||
# resources and sample configuration
|
||||
PLUGIN_RESOURCES = \
|
||||
cc_off.tga \
|
||||
cc_off_hover.tga \
|
||||
cc_on.tga \
|
||||
cc_on_hover.tga \
|
||||
cc_plugin.ini \
|
||||
plugin.txt
|
||||
for(res, PLUGIN_RESOURCES) {
|
||||
data_copy.commands += $(COPY_FILE) $$targetPath(\"$$RES_DIR/$$res\") $$targetPath(\"$$PLUGIN_DIR/$$res\") $$addNewline()
|
||||
}
|
||||
|
||||
# Qt DLLs
|
||||
QT_DLLS = \
|
||||
QtCore4.dll \
|
||||
QtNetwork4.dll
|
||||
for(dll, QT_DLLS) {
|
||||
data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_BINS]/$$dll\") $$targetPath(\"$$SIM_DIR/$$dll\") $$addNewline()
|
||||
}
|
||||
|
||||
# MinGW DLLs
|
||||
MINGW_DLLS = \
|
||||
libgcc_s_dw2-1.dll \
|
||||
mingwm10.dll
|
||||
for(dll, MINGW_DLLS) {
|
||||
data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_BINS]/../../../../../mingw/bin/$$dll\") $$targetPath(\"$$SIM_DIR/$$dll\") $$addNewline()
|
||||
}
|
||||
|
||||
data_copy.target = FORCE
|
||||
QMAKE_EXTRA_TARGETS += data_copy
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file qdebughandler.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "qdebughandler.h"
|
||||
|
||||
void myQDebugHandler(QtMsgType type, const char *msg)
|
||||
{
|
||||
static bool firstRun = true;
|
||||
QString txt;
|
||||
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
txt = QString("Debug: %1").arg(msg);
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
txt = QString("Warning: %1").arg(msg);
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
txt = QString("Critical: %1").arg(msg);
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
txt = QString("Fatal: %1").arg(msg);
|
||||
break;
|
||||
}
|
||||
|
||||
QFile outFile("dbglog.txt");
|
||||
outFile.open(QIODevice::WriteOnly | QIODevice::Append);
|
||||
QTextStream ts(&outFile);
|
||||
QTime time;
|
||||
|
||||
if (firstRun) {
|
||||
ts << endl << endl;
|
||||
firstRun = false;
|
||||
}
|
||||
|
||||
ts << time.currentTime().toString("hh:mm:ss.zzz") << " " << txt << endl;
|
||||
|
||||
if (type == QtFatalMsg)
|
||||
abort();
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file qdebughandler.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef QDEBUGHANDLER_H
|
||||
#define QDEBUGHANDLER_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QTime>
|
||||
|
||||
void myQDebugHandler(QtMsgType type, const char *msg);
|
||||
|
||||
#endif // QDEBUGHANDLER_H
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,55 @@
|
||||
[General]
|
||||
|
||||
; Network settings
|
||||
listen_on_host = 127.0.0.1
|
||||
listen_on_port = 40200
|
||||
send_to_host = 127.0.0.1
|
||||
send_to_port = 40100
|
||||
|
||||
; Channels enumerator, applicable for the AeroSIM RC version 3.90+
|
||||
all_channels = Ch1-Aileron Ch2-Elevator Ch3-Throttle Ch4-Rudder Ch5 Ch6 Ch7 Ch8 Ch9 Ch10-Retracts Ch11-Flaps Ch12-FPV-Pan Ch13-FPV-Tilt Ch14-Brakes Ch15-Spoilers Ch16-Smoke Ch17-Fire Ch18-Flight-Mode Ch19-ALT-Hold Ch20-FPV-Tilt-Hold Ch21-Reset-Model Ch22-MouseTX Ch23-Plugin-1 Ch24-Plugin-2 Ch25-Throttle-Hold Ch26-CareFree Ch27-FPV-Roll Ch28-L-Motor-Dual Ch29-R-Motor-Dual Ch30-Mix Ch31-Mix Ch32-Mix Ch33-Mix Ch34-Mix Ch35-Mix Ch36-Mix Ch37-Mix Ch38-Mix Ch39-Mix
|
||||
|
||||
[Input]
|
||||
|
||||
; Map CopterControl channels to simulator channels
|
||||
; To use internal simulator channels just comment the mapping here
|
||||
cc_channel_1 = Ch1-Aileron
|
||||
cc_channel_2 = Ch2-Elevator
|
||||
cc_channel_3 = Ch3-Throttle
|
||||
cc_channel_4 = Ch4-Rudder
|
||||
;cc_channel_5 = Ch27-FPV-Roll
|
||||
cc_channel_6 = Ch13-FPV-Tilt
|
||||
;cc_channel_7 = Ch12-FPV-Pan
|
||||
;cc_channel_8 =
|
||||
;cc_channel_9 =
|
||||
;cc_channel_10=
|
||||
|
||||
; Control TX or RX (before or after mixes)
|
||||
send_to = RX
|
||||
|
||||
[Output]
|
||||
|
||||
; Map simulator channels to GCS HiTL/CopterControl channels
|
||||
; Only mapped channels will be sent to the GCS
|
||||
sim_channel_1 = Ch1-Aileron
|
||||
sim_channel_2 = Ch2-Elevator
|
||||
sim_channel_3 = Ch3-Throttle
|
||||
sim_channel_4 = Ch4-Rudder
|
||||
sim_channel_5 = Ch23-Plugin-1
|
||||
;sim_channel_6 = Ch27-FPV-Roll
|
||||
sim_channel_7 = Ch13-FPV-Tilt
|
||||
;sim_channel_8 = Ch12-FPV-Pan
|
||||
|
||||
; take values from TX or RX (before or after mixes)
|
||||
take_from = TX
|
||||
|
||||
[Video]
|
||||
|
||||
; Windowed simulator mode configurations
|
||||
; Each resolution defines the upper left corner and width/hight.
|
||||
; User can cycle through all resolutions using the menu command.
|
||||
number_of_resolutions = 2
|
||||
|
||||
; x, y, width, height
|
||||
resolution_1 = 50 50 640 720
|
||||
resolution_2 = 0 0 800 480
|
@ -0,0 +1,86 @@
|
||||
.NAME "CopterControl"
|
||||
|
||||
.HELP_EN "\
|
||||
OpenPilot CopterControl HiTL plugin for AeroSIM RC"
|
||||
|
||||
.IMAGE_OFF "cc_off.tga"
|
||||
.IMAGE_ON "cc_on.tga"
|
||||
.IMAGE_OFF_MOUSE_HOVER "cc_off_hover.tga"
|
||||
.IMAGE_ON_MOUSE_HOVER "cc_on_hover.tga"
|
||||
|
||||
.MENU_ITEM_00_NAME "Enable"
|
||||
.MENU_ITEM_00_TYPE CHECKBOX
|
||||
.MENU_ITEM_00_HAS_SEPARATOR 0
|
||||
.MENU_ITEM_00_MOUSE_RECT_XY 89 91
|
||||
.MENU_ITEM_00_MOUSE_RECT_DXDY 48 48
|
||||
.MENU_ITEM_00_HIDE_MENU_ITEM 0
|
||||
|
||||
.MENU_ITEM_01_NAME "Transmit data"
|
||||
.MENU_ITEM_01_TYPE CHECKBOX
|
||||
.MENU_ITEM_01_HAS_SEPARATOR 0
|
||||
.MENU_ITEM_01_MOUSE_RECT_XY 110 166
|
||||
.MENU_ITEM_01_MOUSE_RECT_DXDY 52 34
|
||||
.MENU_ITEM_01_HIDE_MENU_ITEM 0
|
||||
|
||||
.MENU_ITEM_02_NAME "Receive data"
|
||||
.MENU_ITEM_02_TYPE CHECKBOX
|
||||
.MENU_ITEM_02_HAS_SEPARATOR 1
|
||||
.MENU_ITEM_02_MOUSE_RECT_XY 36 166
|
||||
.MENU_ITEM_02_MOUSE_RECT_DXDY 52 34
|
||||
.MENU_ITEM_02_HIDE_MENU_ITEM 0
|
||||
|
||||
.MENU_ITEM_03_NAME "Change window size and position"
|
||||
.MENU_ITEM_03_TYPE COMMAND
|
||||
.MENU_ITEM_03_HAS_SEPARATOR 0
|
||||
.MENU_ITEM_03_MOUSE_RECT_XY 0 0
|
||||
.MENU_ITEM_03_MOUSE_RECT_DXDY 0 0
|
||||
.MENU_ITEM_03_HIDE_MENU_ITEM 0
|
||||
|
||||
.MENU_ITEM_04_NAME "Move to next waypoint"
|
||||
.MENU_ITEM_04_TYPE COMMAND
|
||||
.MENU_ITEM_04_HAS_SEPARATOR 0
|
||||
.MENU_ITEM_04_MOUSE_RECT_XY 0 0
|
||||
.MENU_ITEM_04_MOUSE_RECT_DXDY 0 0
|
||||
.MENU_ITEM_04_HIDE_MENU_ITEM 0
|
||||
|
||||
.MENU_ITEM_05_NAME "no action"
|
||||
.MENU_ITEM_05_TYPE COMMAND
|
||||
.MENU_ITEM_05_HAS_SEPARATOR 0
|
||||
.MENU_ITEM_05_MOUSE_RECT_XY 0 0
|
||||
.MENU_ITEM_05_MOUSE_RECT_DXDY 0 0
|
||||
.MENU_ITEM_05_HIDE_MENU_ITEM 0
|
||||
|
||||
.MENU_ITEM_06_NAME "Blue LED"
|
||||
.MENU_ITEM_06_TYPE CHECKBOX
|
||||
.MENU_ITEM_06_HAS_SEPARATOR 0
|
||||
.MENU_ITEM_06_MOUSE_RECT_XY 6 40
|
||||
.MENU_ITEM_06_MOUSE_RECT_DXDY 15 12
|
||||
.MENU_ITEM_06_HIDE_MENU_ITEM 1
|
||||
|
||||
.MENU_ITEM_07_NAME "Green LED"
|
||||
.MENU_ITEM_07_TYPE CHECKBOX
|
||||
.MENU_ITEM_07_HAS_SEPARATOR 0
|
||||
.MENU_ITEM_07_MOUSE_RECT_XY 6 52
|
||||
.MENU_ITEM_07_MOUSE_RECT_DXDY 15 12
|
||||
.MENU_ITEM_07_HIDE_MENU_ITEM 1
|
||||
|
||||
.MENU_ITEM_08_NAME "FlightMode 1"
|
||||
.MENU_ITEM_08_TYPE CHECKBOX
|
||||
.MENU_ITEM_08_HAS_SEPARATOR 0
|
||||
.MENU_ITEM_08_MOUSE_RECT_XY 40 19
|
||||
.MENU_ITEM_08_MOUSE_RECT_DXDY 38 38
|
||||
.MENU_ITEM_08_HIDE_MENU_ITEM 1
|
||||
|
||||
.MENU_ITEM_09_NAME "FlightMode 2"
|
||||
.MENU_ITEM_09_TYPE CHECKBOX
|
||||
.MENU_ITEM_09_HAS_SEPARATOR 0
|
||||
.MENU_ITEM_09_MOUSE_RECT_XY 78 19
|
||||
.MENU_ITEM_09_MOUSE_RECT_DXDY 38 38
|
||||
.MENU_ITEM_09_HIDE_MENU_ITEM 1
|
||||
|
||||
.MENU_ITEM_10_NAME "FlightMode 3"
|
||||
.MENU_ITEM_10_TYPE CHECKBOX
|
||||
.MENU_ITEM_10_HAS_SEPARATOR 0
|
||||
.MENU_ITEM_10_MOUSE_RECT_XY 115 19
|
||||
.MENU_ITEM_10_MOUSE_RECT_DXDY 38 38
|
||||
.MENU_ITEM_10_HIDE_MENU_ITEM 1
|
@ -0,0 +1,98 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file settings.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
Settings::Settings(QString settingsPath, QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
settings = new QSettings(settingsPath + "/cc_plugin.ini", QSettings::IniFormat);
|
||||
// default settings
|
||||
sendToHost = "127.0.0.1";
|
||||
sendToPort = 40100;
|
||||
listenOnHost = "127.0.0.1";
|
||||
listenOnPort = 40200;
|
||||
channels.reserve(60);
|
||||
for (quint8 i = 0; i < 10; ++i)
|
||||
inputMap << 255;
|
||||
for (quint8 i = 0; i < 8; ++i)
|
||||
outputMap << 255;
|
||||
sendToRX = true;
|
||||
takeFromTX = true;
|
||||
videoModes << 1 << 50 << 50 << 800 << 600;
|
||||
}
|
||||
|
||||
void Settings::read()
|
||||
{
|
||||
// network
|
||||
listenOnHost = settings->value("listen_on_host", listenOnHost).toString();
|
||||
listenOnPort = settings->value("listen_on_port", listenOnPort).toInt();
|
||||
sendToHost = settings->value("send_to_host", sendToHost).toString();
|
||||
sendToPort = settings->value("send_to_port", sendToPort).toInt();
|
||||
|
||||
QString allChannels = settings->value("all_channels").toString();
|
||||
QString chan;
|
||||
int i = 0;
|
||||
foreach (chan, allChannels.split(" "))
|
||||
channels.insert(chan, i++);
|
||||
|
||||
// inputs
|
||||
QString num = "";
|
||||
QString map = "";
|
||||
for (quint8 i = 0; i < 10; ++i) {
|
||||
num = QString::number(i+1);
|
||||
map = settings->value("Input/cc_channel_" + num).toString();
|
||||
inputMap[i] = channels.value(map, inputMap.at(i));
|
||||
}
|
||||
|
||||
QString sendTo = settings->value("Input/send_to", "RX").toString();
|
||||
sendToRX = (sendTo == "RX") ? true : false;
|
||||
|
||||
// outputs
|
||||
for (quint8 i = 0; i < 8; ++i) {
|
||||
num = QString::number(i+1);
|
||||
map = settings->value("Output/sim_channel_" + num).toString();
|
||||
outputMap[i] = channels.value(map, outputMap.at(i));
|
||||
}
|
||||
|
||||
QString takeFrom = settings->value("Output/take_from", "TX").toString();
|
||||
takeFromTX = (takeFrom == "TX") ? true : false;
|
||||
|
||||
// video
|
||||
quint8 resolutionNum = settings->value("Video/number_of_resolutions", 0).toInt();
|
||||
if (resolutionNum > 0) {
|
||||
videoModes.clear();
|
||||
videoModes << resolutionNum;
|
||||
for (quint8 i = 0; i < resolutionNum; ++i) {
|
||||
num = QString::number(i+1);
|
||||
QString modes = settings->value("Video/resolution_" + num, "0, 0, 640, 480").toString();
|
||||
QString mode;
|
||||
foreach (mode, modes.split(" "))
|
||||
videoModes << mode.toInt();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file settings.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QStringList>
|
||||
#include <QDebug>
|
||||
|
||||
class Settings : public QObject
|
||||
{
|
||||
public:
|
||||
explicit Settings(QString settingsPath, QObject *parent = 0);
|
||||
void read();
|
||||
QString remoteHost() { return sendToHost; }
|
||||
quint16 remotePort() { return sendToPort; }
|
||||
QString localHost() { return listenOnHost; }
|
||||
quint16 localPort() { return listenOnPort; }
|
||||
QList<quint8> getInputMap() { return inputMap; }
|
||||
QList<quint8> getOutputMap() { return outputMap; }
|
||||
bool isToRX() { return sendToRX; }
|
||||
bool isFromTX() { return takeFromTX; }
|
||||
QList<quint16> getVideoModes() { return videoModes; }
|
||||
|
||||
private:
|
||||
QHash<QString, quint8> channels;
|
||||
QSettings *settings;
|
||||
QString sendToHost;
|
||||
quint16 sendToPort;
|
||||
QString listenOnHost;
|
||||
quint16 listenOnPort;
|
||||
QList<quint8> inputMap;
|
||||
QList<quint8> outputMap;
|
||||
bool sendToRX;
|
||||
bool takeFromTX;
|
||||
QList<quint16> videoModes;
|
||||
};
|
||||
|
||||
#endif // SETTINGS_H
|
@ -0,0 +1,228 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file udpconnect.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "udpconnect.h"
|
||||
#include "enums.h"
|
||||
|
||||
UdpSender::UdpSender(const QList<quint8> map,
|
||||
bool isTX,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
qDebug() << this << "UdpSender::UdpSender thread:" << thread();
|
||||
outSocket = NULL;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
channels << 0.0;
|
||||
channelsMap = map;
|
||||
takeFromTX = isTX;
|
||||
packetsSended = 0;
|
||||
}
|
||||
|
||||
UdpSender::~UdpSender()
|
||||
{
|
||||
qDebug() << this << "UdpSender::~UdpSender";
|
||||
if (outSocket)
|
||||
delete outSocket;
|
||||
}
|
||||
|
||||
// public
|
||||
void UdpSender::init(const QString &remoteHost, quint16 remotePort)
|
||||
{
|
||||
qDebug() << this << "UdpSender::init";
|
||||
outHost = remoteHost;
|
||||
outPort = remotePort;
|
||||
outSocket = new QUdpSocket();
|
||||
}
|
||||
|
||||
void UdpSender::sendDatagram(const simToPlugin *stp)
|
||||
{
|
||||
QByteArray data;
|
||||
data.resize(188);
|
||||
QDataStream out(&data, QIODevice::WriteOnly);
|
||||
out.setFloatingPointPrecision(QDataStream::SinglePrecision);
|
||||
|
||||
// magic header, "AERO"
|
||||
out << quint32(0x4153494D);
|
||||
// simulation step
|
||||
out << stp->simTimeStep;
|
||||
// home location
|
||||
out << stp->initPosX << stp->initPosY << stp->initPosZ;
|
||||
out << stp->wpHomeX << stp->wpHomeY << stp->wpHomeLat << stp->wpHomeLong;
|
||||
// position
|
||||
out << stp->posX << stp->posY << stp->posZ;
|
||||
// velocity (world)
|
||||
out << stp->velX << stp->velY << stp->velZ;
|
||||
// angular velocity (model)
|
||||
out << stp->angVelXm << stp->angVelYm << stp->angVelZm;
|
||||
// acceleration (model)
|
||||
out << stp->accelXm << stp->accelYm << stp->accelZm;
|
||||
// coordinates
|
||||
out << stp->latitude << stp->longitude;
|
||||
// sonar
|
||||
out << stp->AGL;
|
||||
// attitude
|
||||
out << stp->heading << stp->pitch << stp->roll;
|
||||
// electric
|
||||
out << stp->voltage << stp->current;
|
||||
// matrix
|
||||
out << stp->axisXx << stp->axisXy << stp->axisXz;
|
||||
out << stp->axisYx << stp->axisYy << stp->axisYz;
|
||||
out << stp->axisZx << stp->axisZy << stp->axisZz;
|
||||
// channels
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
quint8 mapTo = channelsMap.at(i);
|
||||
if (mapTo == 255) // unused channel
|
||||
out << 0.0;
|
||||
else if (takeFromTX) // use values from simulators transmitter
|
||||
out << stp->chSimTX[mapTo];
|
||||
else // direct use values from ESC/motors/ailerons/etc
|
||||
out << stp->chSimRX[mapTo];
|
||||
}
|
||||
|
||||
// packet counter
|
||||
out << packetsSended;
|
||||
|
||||
outSocket->writeDatagram(data, outHost, outPort);
|
||||
++packetsSended;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
UdpReceiver::UdpReceiver(const QList<quint8> map,
|
||||
bool isRX,
|
||||
QObject *parent)
|
||||
: QThread(parent)
|
||||
{
|
||||
qDebug() << this << "UdpReceiver::UdpReceiver thread:" << thread();
|
||||
|
||||
stopped = false;
|
||||
inSocket = NULL;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
channels << -1.0;
|
||||
channelsMap = map;
|
||||
sendToRX = isRX;
|
||||
armed = 0;
|
||||
mode = 0;
|
||||
packetsRecived = 1;
|
||||
}
|
||||
|
||||
UdpReceiver::~UdpReceiver()
|
||||
{
|
||||
qDebug() << this << "UdpReceiver::~UdpReceiver";
|
||||
if (inSocket)
|
||||
delete inSocket;
|
||||
}
|
||||
|
||||
// public
|
||||
void UdpReceiver::init(const QString &localHost, quint16 localPort)
|
||||
{
|
||||
qDebug() << this << "UdpReceiver::init";
|
||||
|
||||
inSocket = new QUdpSocket();
|
||||
qDebug() << this << "inSocket constructed" << inSocket->thread();
|
||||
|
||||
inSocket->bind(QHostAddress(localHost), localPort);
|
||||
}
|
||||
|
||||
void UdpReceiver::run()
|
||||
{
|
||||
qDebug() << this << "UdpReceiver::run start";
|
||||
while (!stopped)
|
||||
onReadyRead();
|
||||
qDebug() << this << "UdpReceiver::run ended";
|
||||
}
|
||||
|
||||
void UdpReceiver::stop()
|
||||
{
|
||||
qDebug() << this << "UdpReceiver::stop";
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
void UdpReceiver::setChannels(pluginToSim *pts)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
quint8 mapTo = channelsMap.at(i);
|
||||
if (mapTo != 255) {
|
||||
float channelValue = qBound(-1.0f, channels.at(i), 1.0f);
|
||||
if (sendToRX) {
|
||||
// direct connect to ESC/motors/ailerons/etc
|
||||
pts->chNewRX[mapTo] = channelValue;
|
||||
pts->chOverRX[mapTo] = true;
|
||||
} else {
|
||||
// replace simulators transmitter
|
||||
pts->chNewTX[mapTo] = channelValue;
|
||||
pts->chOverTX[mapTo] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UdpReceiver::getFlighStatus(quint8 &arm, quint8 &mod)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
arm = armed;
|
||||
mod = mode;
|
||||
}
|
||||
|
||||
// private
|
||||
void UdpReceiver::onReadyRead()
|
||||
{
|
||||
if (!inSocket->waitForReadyRead(8)) // 1/60fps ~= 16.7ms, 1/120fps ~= 8.3ms
|
||||
return;
|
||||
// TODO: add failsafe
|
||||
// if a command not recieved then slowly return all channel to neutral
|
||||
//
|
||||
while (inSocket->hasPendingDatagrams()) {
|
||||
QByteArray datagram;
|
||||
datagram.resize(inSocket->pendingDatagramSize());
|
||||
quint64 datagramSize;
|
||||
datagramSize = inSocket->readDatagram(datagram.data(), datagram.size());
|
||||
|
||||
processDatagram(datagram);
|
||||
}
|
||||
}
|
||||
|
||||
void UdpReceiver::processDatagram(QByteArray &datagram)
|
||||
{
|
||||
QDataStream stream(datagram);
|
||||
stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
|
||||
// check magic header
|
||||
quint32 magic;
|
||||
stream >> magic;
|
||||
if (magic != 0x52434D44) // "RCMD"
|
||||
return;
|
||||
// read channels
|
||||
for (int i = 0; i < 10; ++i)
|
||||
stream >> channels[i];
|
||||
// read flight mode
|
||||
stream >> armed >> mode;
|
||||
// read counter
|
||||
stream >> packetsRecived;
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file udpconnect.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef UDPCONNECT_H
|
||||
#define UDPCONNECT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QUdpSocket>
|
||||
#include <QList>
|
||||
#include <QTime>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include "aerosimrcdatastruct.h"
|
||||
|
||||
class UdpSender : public QObject
|
||||
{
|
||||
// Q_OBJECT
|
||||
public:
|
||||
explicit UdpSender(const QList<quint8> map, bool isTX, QObject *parent = 0);
|
||||
~UdpSender();
|
||||
void init(const QString &remoteHost, quint16 remotePort);
|
||||
void sendDatagram(const simToPlugin *stp);
|
||||
quint32 pcks() { return packetsSended; }
|
||||
|
||||
private:
|
||||
QUdpSocket *outSocket;
|
||||
QHostAddress outHost;
|
||||
quint16 outPort;
|
||||
QList<float> channels;
|
||||
QList<quint8> channelsMap;
|
||||
bool takeFromTX;
|
||||
quint32 packetsSended;
|
||||
};
|
||||
|
||||
|
||||
class UdpReceiver : public QThread
|
||||
{
|
||||
// Q_OBJECT
|
||||
public:
|
||||
explicit UdpReceiver(const QList<quint8> map, bool isRX, QObject *parent = 0);
|
||||
~UdpReceiver();
|
||||
void init(const QString &localHost, quint16 localPort);
|
||||
void run();
|
||||
void stop();
|
||||
// function getChannels for other threads
|
||||
void setChannels(pluginToSim *pts);
|
||||
void getFlighStatus(quint8 &arm, quint8 &mod);
|
||||
quint8 getArmed() { return armed; }
|
||||
quint8 getMode() { return mode; }
|
||||
quint32 pcks() { return packetsRecived; }
|
||||
|
||||
private:
|
||||
volatile bool stopped;
|
||||
QMutex mutex;
|
||||
QUdpSocket *inSocket;
|
||||
QList<float> channels;
|
||||
QList<quint8> channelsMap;
|
||||
bool sendToRX;
|
||||
quint8 armed;
|
||||
quint8 mode;
|
||||
quint32 packetsRecived;
|
||||
void onReadyRead();
|
||||
void processDatagram(QByteArray &datagram);
|
||||
};
|
||||
|
||||
#endif // UDPCONNECT_H
|
@ -0,0 +1,17 @@
|
||||
include(../../../../../openpilotgcs.pri)
|
||||
|
||||
QT += core gui network
|
||||
|
||||
TEMPLATE = app
|
||||
TARGET = udp_test
|
||||
DESTDIR = $$GCS_APP_PATH
|
||||
|
||||
HEADERS += \
|
||||
udptestwidget.h
|
||||
|
||||
SOURCES += \
|
||||
udptestmain.cpp \
|
||||
udptestwidget.cpp
|
||||
|
||||
FORMS += \
|
||||
udptestwidget.ui
|
@ -0,0 +1,38 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file udptestmain.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin test utility
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <QApplication>
|
||||
#include "udptestwidget.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
Widget w;
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
@ -0,0 +1,537 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file udptestwidget.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin test utility
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "udptestwidget.h"
|
||||
#include "ui_udptestwidget.h"
|
||||
|
||||
Widget::Widget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::Widget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
inSocket = NULL;
|
||||
outSocket = NULL;
|
||||
screenTimeout.start();
|
||||
packetCounter = 0;
|
||||
|
||||
autoSendTimer = new QTimer(this);
|
||||
connect(autoSendTimer, SIGNAL(timeout()), this, SLOT(sendDatagram()), Qt::DirectConnection);
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
{
|
||||
if(outSocket) {
|
||||
delete outSocket;
|
||||
}
|
||||
if(inSocket) {
|
||||
delete inSocket;
|
||||
}
|
||||
delete ui;
|
||||
}
|
||||
|
||||
// private slots //////////////////////////////////////////////////////////////
|
||||
|
||||
void Widget::on_btReciveStart_clicked()
|
||||
{
|
||||
on_btReciveStop_clicked();
|
||||
|
||||
inSocket = new QUdpSocket();
|
||||
QString host = ui->localHost->text();
|
||||
quint16 port = ui->localPort->text().toInt();
|
||||
|
||||
if (inSocket->bind(QHostAddress(host), port)) {
|
||||
connect(inSocket, SIGNAL(readyRead()),
|
||||
this, SLOT(readDatagram()), Qt::DirectConnection);
|
||||
|
||||
ui->listWidget->addItem("bind ok");
|
||||
ui->btReciveStop->setEnabled(1);
|
||||
ui->localHost->setDisabled(1);
|
||||
ui->localPort->setDisabled(1);
|
||||
ui->btReciveStart->setDisabled(1);
|
||||
} else {
|
||||
ui->listWidget->addItem("bind error: " + inSocket->errorString());
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::on_btReciveStop_clicked()
|
||||
{
|
||||
if(inSocket) {
|
||||
delete inSocket;
|
||||
inSocket = NULL;
|
||||
ui->listWidget->addItem("unbind ok");
|
||||
} else {
|
||||
ui->listWidget->addItem("socket not found");
|
||||
}
|
||||
ui->btReciveStart->setEnabled(1);
|
||||
ui->localHost->setEnabled(1);
|
||||
ui->localPort->setEnabled(1);
|
||||
ui->btReciveStop->setDisabled(1);
|
||||
}
|
||||
|
||||
void Widget::on_btTransmitStart_clicked()
|
||||
{
|
||||
on_btTransmitStop_clicked();
|
||||
|
||||
outSocket = new QUdpSocket();
|
||||
outHost = ui->simHost->text();
|
||||
outPort = ui->simPort->text().toInt();
|
||||
|
||||
ui->listWidget->addItem("transmit started");
|
||||
ui->btTransmitStop->setEnabled(1);
|
||||
ui->simHost->setDisabled(1);
|
||||
ui->simPort->setDisabled(1);
|
||||
ui->btTransmitStart->setDisabled(1);
|
||||
}
|
||||
|
||||
void Widget::on_btTransmitStop_clicked()
|
||||
{
|
||||
if(outSocket) {
|
||||
delete outSocket;
|
||||
outSocket = NULL;
|
||||
ui->listWidget->addItem("transmit stopped");
|
||||
} else {
|
||||
ui->listWidget->addItem("transmit socket not found");
|
||||
}
|
||||
ui->btTransmitStart->setEnabled(1);
|
||||
ui->simHost->setEnabled(1);
|
||||
ui->simPort->setEnabled(1);
|
||||
ui->btTransmitStop->setDisabled(1);
|
||||
}
|
||||
|
||||
void Widget::readDatagram()
|
||||
{
|
||||
while (inSocket->hasPendingDatagrams()) {
|
||||
QByteArray datagram;
|
||||
datagram.resize(inSocket->pendingDatagramSize());
|
||||
QHostAddress sender;
|
||||
quint16 senderPort;
|
||||
quint64 datagramSize = inSocket->readDatagram(datagram.data(), datagram.size(),
|
||||
&sender, &senderPort);
|
||||
Q_UNUSED(datagramSize);
|
||||
|
||||
processDatagram(datagram);
|
||||
if (ui->autoAnswer->isChecked())
|
||||
sendDatagram();
|
||||
}
|
||||
}
|
||||
|
||||
// private ////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Widget::processDatagram(const QByteArray &data)
|
||||
{
|
||||
QByteArray buf = data;
|
||||
QDataStream stream(&buf, QIODevice::ReadOnly);
|
||||
stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
|
||||
|
||||
// check magic header
|
||||
quint32 magic;
|
||||
stream >> magic;
|
||||
if (magic == 0x4153494D) { // "AERO"
|
||||
float timeStep,
|
||||
homeX, homeY, homeZ,
|
||||
WpHX, WpHY, WpLat, WpLon,
|
||||
posX, posY, posZ,
|
||||
velX, velY, velZ,
|
||||
angX, angY, angZ,
|
||||
accX, accY, accZ,
|
||||
lat, lon, alt,
|
||||
head, pitch, roll,
|
||||
volt, curr,
|
||||
rx, ry, rz, fx, fy, fz, ux, uy, uz,
|
||||
chAil, chEle, chThr, chRud, chPlg1, chPlg2, chFpv1, chFpv2;
|
||||
|
||||
stream >> timeStep;
|
||||
stream >> homeX >> homeY >> homeZ;
|
||||
stream >> WpHX >> WpHY >> WpLat >> WpLon;
|
||||
stream >> posX >> posY >> posZ;
|
||||
stream >> velX >> velY >> velZ;
|
||||
stream >> angX >> angY >> angZ;
|
||||
stream >> accX >> accY >> accZ;
|
||||
stream >> lat >> lon >> alt;
|
||||
stream >> head >> pitch >> roll;
|
||||
stream >> volt >> curr;
|
||||
stream >> rx >> ry >> rz >> fx >> fy >> fz >> ux >> uy >> uz;
|
||||
stream >> chAil >> chEle >> chThr >> chRud >> chPlg1 >> chPlg2 >> chFpv1 >> chFpv2;
|
||||
stream >> packetCounter;
|
||||
|
||||
if(ui->tabWidget->currentIndex() != 0)
|
||||
return;
|
||||
|
||||
if (screenTimeout.elapsed() < 200)
|
||||
return;
|
||||
|
||||
ui->listWidget->clear();
|
||||
/*
|
||||
ui->listWidget->addItem("time step (s)");
|
||||
ui->listWidget->addItem(QString("%1")
|
||||
.arg(timeStep);
|
||||
ui->listWidget->addItem("home location (m)");
|
||||
ui->listWidget->addItem(QString("%1, %2, %3")
|
||||
.arg(homeX, 7, 'f', 4)
|
||||
.arg(homeY, 7, 'f', 4)
|
||||
.arg(homeZ, 7, 'f', 4));
|
||||
ui->listWidget->addItem("home waypoint");
|
||||
ui->listWidget->addItem(QString("%1, %2, %3, %4")
|
||||
.arg(WpHX, 7, 'f', 4)
|
||||
.arg(WpHY, 7, 'f', 4)
|
||||
.arg(WpLat, 7, 'f', 4)
|
||||
.arg(WpLon, 7, 'f', 4));
|
||||
ui->listWidget->addItem("model position (m)");
|
||||
ui->listWidget->addItem(QString("%1, %2, %3")
|
||||
.arg(posX, 7, 'f', 4)
|
||||
.arg(posY, 7, 'f', 4)
|
||||
.arg(posZ, 7, 'f', 4));
|
||||
ui->listWidget->addItem("model velocity (m/s)");
|
||||
ui->listWidget->addItem(QString("%1, %2, %3")
|
||||
.arg(velX, 7, 'f', 4)
|
||||
.arg(velY, 7, 'f', 4)
|
||||
.arg(velZ, 7, 'f', 4));
|
||||
ui->listWidget->addItem("model angular velocity (rad/s)");
|
||||
ui->listWidget->addItem(QString("%1, %2, %3")
|
||||
.arg(angX, 7, 'f', 4)
|
||||
.arg(angY, 7, 'f', 4)
|
||||
.arg(angZ, 7, 'f', 4));
|
||||
ui->listWidget->addItem("model acceleration (m/s/s)");
|
||||
ui->listWidget->addItem(QString("%1, %2, %3")
|
||||
.arg(accX, 7, 'f', 4)
|
||||
.arg(accY, 7, 'f', 4)
|
||||
.arg(accZ, 7, 'f', 4));
|
||||
ui->listWidget->addItem("model coordinates (deg, deg, m)");
|
||||
ui->listWidget->addItem(QString("%1, %2, %3")
|
||||
.arg(lat, 7, 'f', 4)
|
||||
.arg(lon, 7, 'f', 4)
|
||||
.arg(alt, 7, 'f', 4));
|
||||
ui->listWidget->addItem("model electrics");
|
||||
ui->listWidget->addItem(QString("%1V, %2A")
|
||||
.arg(volt, 7, 'f', 4)
|
||||
.arg(curr, 7, 'f', 4));
|
||||
ui->listWidget->addItem("channels");
|
||||
ui->listWidget->addItem(QString("%1 %2 %3 %4 %5 %6 %7 %8")
|
||||
.arg(chAil, 6, 'f', 3)
|
||||
.arg(chEle, 6, 'f', 3)
|
||||
.arg(chThr, 6, 'f', 3)
|
||||
.arg(chRud, 6, 'f', 3)
|
||||
.arg(chPlg1, 6, 'f', 3)
|
||||
.arg(chPlg2, 6, 'f', 3)
|
||||
.arg(chFpv1, 6, 'f', 3)
|
||||
.arg(chFpv2, 6, 'f', 3));
|
||||
ui->listWidget->addItem("datagram size (bytes), packet counter");
|
||||
ui->listWidget->addItem(QString("%1 %2")
|
||||
.arg(data.size())
|
||||
.arg(packetCounter));
|
||||
*/
|
||||
|
||||
// matrix calculation start
|
||||
// model matrix
|
||||
QMatrix4x4 m = QMatrix4x4( fy, fx, -fz, 0.0,
|
||||
ry, rx, -rz, 0.0,
|
||||
-uy, -ux, uz, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0);
|
||||
m.optimize();
|
||||
|
||||
// world matrix
|
||||
QMatrix4x4 w = m.inverted();
|
||||
|
||||
// model quat
|
||||
QQuaternion q;
|
||||
asMatrix2Quat(m, q);
|
||||
|
||||
// model roll, pitch, yaw
|
||||
QVector3D rpy;
|
||||
asMatrix2RPY(m, rpy);
|
||||
|
||||
// sonar
|
||||
float sAlt = 5.0;
|
||||
if ((alt < (sAlt * 2.0)) && (roll < 0.35) && (pitch < 0.35)) {
|
||||
float x = alt * qTan(roll);
|
||||
float y = alt * qTan(pitch);
|
||||
float h = QVector3D(x, y, alt).length();
|
||||
sAlt = qMin(h, sAlt);
|
||||
}
|
||||
|
||||
ui->listWidget->addItem("sonar altitude");
|
||||
ui->listWidget->addItem(QString("%1")
|
||||
.arg(sAlt, 8, 'f', 5));
|
||||
ui->listWidget->addItem("vectors");
|
||||
ui->listWidget->addItem(QString(" X Y Z"));
|
||||
ui->listWidget->addItem(QString("R: %1 %2 %3\nF: %4 %5 %6\nU: %7 %8 %9")
|
||||
.arg(rx, 8, 'f', 5).arg(ry, 8, 'f', 5).arg(rz, 8, 'f', 5)
|
||||
.arg(fx, 8, 'f', 5).arg(fy, 8, 'f', 5).arg(fz, 8, 'f', 5)
|
||||
.arg(ux, 8, 'f', 5).arg(uy, 8, 'f', 5).arg(uz, 8, 'f', 5));
|
||||
ui->listWidget->addItem("CC model matrix");
|
||||
ui->listWidget->addItem(QString(" %1 %2 %3\n %4 %5 %6\n %7 %8 %9")
|
||||
.arg(m(0, 0), 8, 'f', 5).arg(m(0, 1), 8, 'f', 5).arg(m(0, 2), 8, 'f', 5)
|
||||
.arg(m(1, 0), 8, 'f', 5).arg(m(1, 1), 8, 'f', 5).arg(m(1, 2), 8, 'f', 5)
|
||||
.arg(m(2, 0), 8, 'f', 5).arg(m(2, 1), 8, 'f', 5).arg(m(2, 2), 8, 'f', 5));
|
||||
ui->listWidget->addItem("CC world matrix");
|
||||
ui->listWidget->addItem(QString(" %1 %2 %3\n %4 %5 %6\n %7 %8 %9")
|
||||
.arg(w(0, 0), 8, 'f', 5).arg(w(0, 1), 8, 'f', 5).arg(w(0, 2), 8, 'f', 5)
|
||||
.arg(w(1, 0), 8, 'f', 5).arg(w(1, 1), 8, 'f', 5).arg(w(1, 2), 8, 'f', 5)
|
||||
.arg(w(2, 0), 8, 'f', 5).arg(w(2, 1), 8, 'f', 5).arg(w(2, 2), 8, 'f', 5));
|
||||
ui->listWidget->addItem("CC quaternion");
|
||||
ui->listWidget->addItem(QString("%1, %2, %3, %4")
|
||||
.arg(q.x(), 7, 'f', 4)
|
||||
.arg(q.y(), 7, 'f', 4)
|
||||
.arg(q.z(), 7, 'f', 4)
|
||||
.arg(q.scalar(), 7, 'f', 4));
|
||||
ui->listWidget->addItem("model attitude (deg)");
|
||||
ui->listWidget->addItem(QString("%1, %2, %3")
|
||||
.arg(roll*RAD2DEG, 7, 'f', 4)
|
||||
.arg(pitch*RAD2DEG, 7, 'f', 4)
|
||||
.arg(head*RAD2DEG, 7, 'f', 4));
|
||||
ui->listWidget->addItem("CC attitude calculated (deg)");
|
||||
ui->listWidget->addItem(QString("%1, %2, %3")
|
||||
.arg(rpy.x(), 7, 'f', 4)
|
||||
.arg(rpy.y(), 7, 'f', 4)
|
||||
.arg(rpy.z(), 7, 'f', 4));
|
||||
|
||||
screenTimeout.restart();
|
||||
|
||||
} else if (magic == 0x52434D44) { // "RCMD"
|
||||
qreal ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10;
|
||||
stream >> ch1 >> ch2 >> ch3 >> ch4 >> ch5 >> ch6 >> ch7 >> ch8 >> ch9 >> ch10;
|
||||
quint8 armed, mode;
|
||||
stream >> armed >> mode;
|
||||
|
||||
if(ui->tabWidget->currentIndex() == 0) {
|
||||
if (screenTimeout.elapsed() < 200)
|
||||
return;
|
||||
ui->listWidget->clear();
|
||||
ui->listWidget->addItem("channels");
|
||||
ui->listWidget->addItem("CH1: " + QString::number(ch1));
|
||||
ui->listWidget->addItem("CH2: " + QString::number(ch2));
|
||||
ui->listWidget->addItem("CH3: " + QString::number(ch3));
|
||||
ui->listWidget->addItem("CH4: " + QString::number(ch4));
|
||||
ui->listWidget->addItem("CH5: " + QString::number(ch5));
|
||||
ui->listWidget->addItem("CH6: " + QString::number(ch6));
|
||||
ui->listWidget->addItem("CH7: " + QString::number(ch7));
|
||||
ui->listWidget->addItem("CH8: " + QString::number(ch8));
|
||||
ui->listWidget->addItem("CH9: " + QString::number(ch9));
|
||||
ui->listWidget->addItem("CH10:" + QString::number(ch10));
|
||||
ui->listWidget->addItem("armed:" + QString::number(armed));
|
||||
ui->listWidget->addItem("fmode:" + QString::number(mode));
|
||||
}
|
||||
screenTimeout.restart();
|
||||
} else {
|
||||
qDebug() << "unknown magic:" << magic;
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::sendDatagram()
|
||||
{
|
||||
if(!outSocket)
|
||||
return;
|
||||
|
||||
float ch[10]; // = {0,0,0,0,0,0,0,0,0,0};
|
||||
quint8 armed;
|
||||
quint8 fmode;
|
||||
const float coeff = 1.0 / 512.0;
|
||||
|
||||
ch[0] = ui->ch1->value() * coeff;
|
||||
ch[1] = ui->ch2->value() * coeff;
|
||||
ch[2] = ui->ch3->value() * coeff;
|
||||
ch[3] = ui->ch4->value() * coeff;
|
||||
ch[4] = ui->ch5->value() * coeff;
|
||||
ch[5] = ui->ch6->value() * coeff;
|
||||
ch[6] = ui->ch7->value() * coeff;
|
||||
ch[7] = ui->ch8->value() * coeff;
|
||||
ch[8] = ui->ch9->value() * coeff;
|
||||
ch[9] = ui->ch10->value() * coeff;
|
||||
|
||||
armed = (ui->disarmed->isChecked()) ? 0 : (ui->arming->isChecked()) ? 1 : 2;
|
||||
fmode = ui->flightMode->value();
|
||||
|
||||
QByteArray data;
|
||||
// 50 - current size of values, 4(quint32) + 10*4(float) + 2*1(quint8) + 4(quint32)
|
||||
data.resize(50);
|
||||
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||
stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
|
||||
|
||||
// magic header, "RCMD"
|
||||
stream << quint32(0x52434D44);
|
||||
// send channels
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
stream << ch[i];
|
||||
}
|
||||
// send armed and mode
|
||||
stream << armed << fmode;
|
||||
// send readed counter
|
||||
stream << packetCounter;
|
||||
|
||||
if (outSocket->writeDatagram(data, outHost, outPort) == -1) {
|
||||
qDebug() << "write failed: outHost" << outHost << " "
|
||||
<< "outPort " << outPort << " "
|
||||
<< outSocket->errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::on_autoSend_clicked()
|
||||
{
|
||||
autoSendTimer->start(100);
|
||||
qDebug() << "timer start";
|
||||
}
|
||||
|
||||
void Widget::on_autoAnswer_clicked()
|
||||
{
|
||||
autoSendTimer->stop();
|
||||
qDebug() << "timer stop";
|
||||
}
|
||||
|
||||
// transfomations
|
||||
|
||||
void Widget::asMatrix2Quat(const QMatrix4x4 &m, QQuaternion &q)
|
||||
{
|
||||
qreal w, x, y, z;
|
||||
|
||||
// w always >= 0
|
||||
w = qSqrt(qMax(0.0, 1.0 + m(0, 0) + m(1, 1) + m(2, 2))) / 2.0;
|
||||
x = qSqrt(qMax(0.0, 1.0 + m(0, 0) - m(1, 1) - m(2, 2))) / 2.0;
|
||||
y = qSqrt(qMax(0.0, 1.0 - m(0, 0) + m(1, 1) - m(2, 2))) / 2.0;
|
||||
z = qSqrt(qMax(0.0, 1.0 - m(0, 0) - m(1, 1) + m(2, 2))) / 2.0;
|
||||
|
||||
x = copysign(x, (m(1, 2) - m(2, 1)));
|
||||
y = copysign(y, (m(2, 0) - m(0, 2)));
|
||||
z = copysign(z, (m(0, 1) - m(1, 0)));
|
||||
|
||||
q.setScalar(w);
|
||||
q.setX(x);
|
||||
q.setY(y);
|
||||
q.setZ(z);
|
||||
}
|
||||
|
||||
void Widget::asQuat2RPY(const QQuaternion &q, QVector3D &rpy)
|
||||
{
|
||||
qreal roll;
|
||||
qreal pitch;
|
||||
qreal yaw;
|
||||
|
||||
const qreal d2 = 2.0;
|
||||
const qreal qss = q.scalar() * q.scalar();
|
||||
const qreal qxx = q.x() * q.x();
|
||||
const qreal qyy = q.y() * q.y();
|
||||
const qreal qzz = q.z() * q.z();
|
||||
|
||||
qreal test = -d2 * (q.x() * q.z() - q.scalar() * q.y());
|
||||
if (qFabs(test) > 0.998) {
|
||||
// ~86.3°, gimbal lock
|
||||
qreal R10 = d2 * (q.x() * q.y() - q.scalar() * q.z());
|
||||
qreal R11 = qss - qxx + qyy - qzz;
|
||||
|
||||
roll = 0.0;
|
||||
pitch = copysign(M_PI_2, test);
|
||||
yaw = qAtan2(-R10, R11);
|
||||
} else {
|
||||
qreal R12 = d2 * (q.y() * q.z() + q.scalar() * q.x());
|
||||
qreal R22 = qss - qxx - qyy + qzz;
|
||||
qreal R01 = d2 * (q.x() * q.y() + q.scalar() * q.z());
|
||||
qreal R00 = qss + qxx - qyy - qzz;
|
||||
|
||||
roll = qAtan2(R12, R22);
|
||||
pitch = qAsin(test);
|
||||
yaw = qAtan2(R01, R00);
|
||||
}
|
||||
rpy.setX(RAD2DEG * roll);
|
||||
rpy.setY(RAD2DEG * pitch);
|
||||
rpy.setZ(RAD2DEG * yaw);
|
||||
}
|
||||
|
||||
void Widget::asMatrix2RPY(const QMatrix4x4 &m, QVector3D &rpy)
|
||||
{
|
||||
qreal roll;
|
||||
qreal pitch;
|
||||
qreal yaw;
|
||||
|
||||
if (qFabs(m(0, 2)) > 0.998) {
|
||||
// ~86.3°, gimbal lock
|
||||
roll = 0.0;
|
||||
pitch = copysign(M_PI_2, -m(0, 2));
|
||||
yaw = qAtan2(-m(1, 0), m(1, 1));
|
||||
} else {
|
||||
roll = qAtan2(m(1, 2), m(2, 2));
|
||||
pitch = qAsin(-m(0, 2));
|
||||
yaw = qAtan2(m(0, 1), m(0, 0));
|
||||
}
|
||||
|
||||
rpy.setX(roll * RAD2DEG);
|
||||
rpy.setY(pitch * RAD2DEG);
|
||||
rpy.setZ(yaw * RAD2DEG);
|
||||
}
|
||||
|
||||
/* // not used
|
||||
|
||||
void Widget::ccRPY2Quat(const QVector3D &rpy, QQuaternion &q)
|
||||
{
|
||||
float phi, theta, psi;
|
||||
float cphi, sphi, ctheta, stheta, cpsi, spsi;
|
||||
|
||||
phi = rpy.x() / 2;
|
||||
theta = rpy.y() / 2;
|
||||
psi = rpy.z() / 2;
|
||||
cphi = cosf(phi);
|
||||
sphi = sinf(phi);
|
||||
ctheta = cosf(theta);
|
||||
stheta = sinf(theta);
|
||||
cpsi = cosf(psi);
|
||||
spsi = sinf(psi);
|
||||
|
||||
q.setScalar(cphi * ctheta * cpsi + sphi * stheta * spsi);
|
||||
q.setX(sphi * ctheta * cpsi - cphi * stheta * spsi);
|
||||
q.setY(cphi * stheta * cpsi + sphi * ctheta * spsi);
|
||||
q.setZ(cphi * ctheta * spsi - sphi * stheta * cpsi);
|
||||
|
||||
if (q.scalar() < 0) { // q0 always positive for uniqueness
|
||||
q.setScalar(-q.scalar());
|
||||
q.setX(-q.x());
|
||||
q.setY(-q.y());
|
||||
q.setZ(-q.z());
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::ccQuat2Matrix(const QQuaternion &q, QMatrix4x4 &m)
|
||||
{
|
||||
float q0s = q.scalar() * q.scalar();
|
||||
float q1s = q.x() * q.x();
|
||||
float q2s = q.y() * q.y();
|
||||
float q3s = q.z() * q.z();
|
||||
|
||||
float m00 = q0s + q1s - q2s - q3s;
|
||||
float m01 = 2 * (q.x() * q.y() + q.scalar() * q.z());
|
||||
float m02 = 2 * (q.x() * q.z() - q.scalar() * q.y());
|
||||
float m10 = 2 * (q.x() * q.y() - q.scalar() * q.z());
|
||||
float m11 = q0s - q1s + q2s - q3s;
|
||||
float m12 = 2 * (q.y() * q.z() + q.scalar() * q.x());
|
||||
float m20 = 2 * (q.x() * q.z() + q.scalar() * q.y());
|
||||
float m21 = 2 * (q.y() * q.z() - q.scalar() * q.x());
|
||||
float m22 = q0s - q1s - q2s + q3s;
|
||||
|
||||
m = QMatrix4x4(m00, m01, m02, 0,
|
||||
m10, m11, m12, 0,
|
||||
m20, m21, m22, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
*/
|
@ -0,0 +1,91 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file udptestwidget.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup 3rdParty Third-party integration
|
||||
* @{
|
||||
* @addtogroup AeroSimRC AeroSimRC proxy plugin
|
||||
* @{
|
||||
* @brief AeroSimRC simulator to HITL proxy plugin test utility
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef UDPTESTWIDGET_H
|
||||
#define UDPTESTWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QUdpSocket>
|
||||
#include <QTime>
|
||||
#include <qmath.h>
|
||||
#include <QVector3D>
|
||||
#include <QMatrix4x4>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Ui {
|
||||
class Widget;
|
||||
}
|
||||
|
||||
const float RAD2DEG = (float)(180.0/M_PI);
|
||||
const float DEG2RAD = (float)(M_PI/180.0);
|
||||
|
||||
class Widget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Widget(QWidget *parent = 0);
|
||||
~Widget();
|
||||
|
||||
private slots:
|
||||
void on_btReciveStart_clicked();
|
||||
void on_btReciveStop_clicked();
|
||||
void on_btTransmitStart_clicked();
|
||||
void on_btTransmitStop_clicked();
|
||||
|
||||
void readDatagram();
|
||||
void sendDatagram();
|
||||
|
||||
void on_autoSend_clicked();
|
||||
|
||||
void on_autoAnswer_clicked();
|
||||
|
||||
private:
|
||||
Ui::Widget *ui;
|
||||
|
||||
QTime screenTimeout;
|
||||
QUdpSocket *inSocket;
|
||||
QUdpSocket *outSocket;
|
||||
QHostAddress outHost;
|
||||
quint16 outPort;
|
||||
quint32 packetCounter;
|
||||
|
||||
void processDatagram(const QByteArray &data);
|
||||
QTimer *autoSendTimer;
|
||||
|
||||
void asMatrix2Quat(const QMatrix4x4 &m, QQuaternion &q);
|
||||
void asMatrix2RPY(const QMatrix4x4 &m, QVector3D &rpy);
|
||||
void asQuat2RPY(const QQuaternion &q, QVector3D &rpy);
|
||||
|
||||
/* // not used
|
||||
* void ccRPY2Quat(const QVector3D &rpy, QQuaternion &q);
|
||||
* void ccQuat2Matrix(const QQuaternion &q, QMatrix4x4 &m);
|
||||
*/
|
||||
};
|
||||
|
||||
#endif // UDPTESTWIDGET_H
|
@ -0,0 +1,940 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Widget</class>
|
||||
<widget class="QWidget" name="Widget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>440</width>
|
||||
<height>525</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">udp_test</string>
|
||||
</property>
|
||||
<property name="windowFilePath">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="4">
|
||||
<widget class="QPushButton" name="btReciveStart">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Connect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLineEdit" name="localPort">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">40100</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="localHost">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">127.0.0.1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lbLocalHost">
|
||||
<property name="text">
|
||||
<string notr="true">sim host</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lbSimHost">
|
||||
<property name="text">
|
||||
<string notr="true">local host:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="lbSimPort">
|
||||
<property name="text">
|
||||
<string notr="true">local port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QPushButton" name="btReciveStop">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Disconnect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="simHost">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">127.0.0.1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="lbLocalPort">
|
||||
<property name="text">
|
||||
<string notr="true">sim port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLineEdit" name="simPort">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">40200</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QPushButton" name="btTransmitStart">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Transmit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<widget class="QPushButton" name="btTransmitStop">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Stop</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_1">
|
||||
<attribute name="title">
|
||||
<string notr="true">raw data</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Terminal</family>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string notr="true">channels</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>send data</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="autoAnswer">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">answer on recieve</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="autoSend">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">auto send</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Flight mode</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSlider" name="flightMode">
|
||||
<property name="maximum">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Armed state</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="disarmed">
|
||||
<property name="text">
|
||||
<string>Disarmed</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="arming">
|
||||
<property name="text">
|
||||
<string>Arming</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="armed">
|
||||
<property name="text">
|
||||
<string>Armed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Channels</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lbCH1n">
|
||||
<property name="text">
|
||||
<string notr="true">CH1</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSlider" name="ch1">
|
||||
<property name="minimum">
|
||||
<number>-511</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>512</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="lbCH1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lbCH2n">
|
||||
<property name="text">
|
||||
<string notr="true">CH2</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSlider" name="ch2">
|
||||
<property name="minimum">
|
||||
<number>-511</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>512</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="lbCH2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lbCH3n">
|
||||
<property name="text">
|
||||
<string notr="true">CH3</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSlider" name="ch3">
|
||||
<property name="minimum">
|
||||
<number>-511</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>512</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="lbCH3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="lbCH4n">
|
||||
<property name="text">
|
||||
<string notr="true">CH4</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSlider" name="ch4">
|
||||
<property name="minimum">
|
||||
<number>-511</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>512</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="lbCH4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="lbCH5n">
|
||||
<property name="text">
|
||||
<string notr="true">CH5</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSlider" name="ch5">
|
||||
<property name="minimum">
|
||||
<number>-511</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>512</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLabel" name="lbCH5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="lbCH6n">
|
||||
<property name="text">
|
||||
<string notr="true">CH6</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLabel" name="lbCH6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="lbCH7n">
|
||||
<property name="text">
|
||||
<string notr="true">Ch7</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<widget class="QLabel" name="lbCH7">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="lbCH8n">
|
||||
<property name="text">
|
||||
<string notr="true">Ch8</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<widget class="QLabel" name="lbCH8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="lbCH9n">
|
||||
<property name="text">
|
||||
<string notr="true">Ch9</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QSlider" name="ch9">
|
||||
<property name="minimum">
|
||||
<number>-511</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>512</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="2">
|
||||
<widget class="QLabel" name="lbCH9">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="lbCH10n">
|
||||
<property name="text">
|
||||
<string notr="true">Ch10</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QSlider" name="ch10">
|
||||
<property name="minimum">
|
||||
<number>-511</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>512</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="2">
|
||||
<widget class="QLabel" name="lbCH10">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSlider" name="ch6">
|
||||
<property name="minimum">
|
||||
<number>-511</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>512</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QSlider" name="ch7">
|
||||
<property name="minimum">
|
||||
<number>-511</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>512</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QSlider" name="ch8">
|
||||
<property name="minimum">
|
||||
<number>-511</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>512</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksAbove</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -1,27 +1,5 @@
|
||||
TEMPLATE = lib
|
||||
TARGET = HITLv2
|
||||
QT += network
|
||||
include(../../openpilotgcsplugin.pri)
|
||||
include(hitlv2_dependencies.pri)
|
||||
HEADERS += \
|
||||
aerosimrc.h \
|
||||
hitlv2configuration.h \
|
||||
hitlv2factory.h \
|
||||
hitlv2gadget.h \
|
||||
hitlv2optionspage.h \
|
||||
hitlv2plugin.h \
|
||||
hitlv2widget.h \
|
||||
simulatorv2.h
|
||||
SOURCES += \
|
||||
aerosimrc.cpp \
|
||||
hitlv2configuration.cpp \
|
||||
hitlv2factory.cpp \
|
||||
hitlv2gadget.cpp \
|
||||
hitlv2optionspage.cpp \
|
||||
hitlv2plugin.cpp \
|
||||
hitlv2widget.cpp \
|
||||
simulatorv2.cpp
|
||||
OTHER_FILES += hitlv2.pluginspec
|
||||
FORMS += \
|
||||
hitlv2optionspage.ui \
|
||||
hitlv2widget.ui
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS = plugin aerosimrc
|
||||
|
||||
plugin.file = plugin.pro
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file hitlconfiguration.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2configuration.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file hitlconfiguration.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2configuration.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file hitlfactory.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2factory.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -24,6 +24,7 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "hitlv2factory.h"
|
||||
#include "hitlv2widget.h"
|
||||
#include "hitlv2gadget.h"
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file hitlfactory.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2factory.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file hitl.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2gadget.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -24,6 +24,7 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "hitlv2gadget.h"
|
||||
#include "hitlv2widget.h"
|
||||
#include "hitlv2configuration.h"
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file hitl.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2gadget.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file hitloptionspage.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2optionspage.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file hitloptionspage.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2optionspage.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file mapplugin.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2plugin.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -24,6 +24,7 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "hitlv2plugin.h"
|
||||
#include "hitlv2factory.h"
|
||||
#include <QtPlugin>
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file browserplugin.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2plugin.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file hitlwidget.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2widget.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -24,6 +24,7 @@
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "hitlv2widget.h"
|
||||
#include "ui_hitlv2widget.h"
|
||||
#include <QDebug>
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file hitlwidget.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file hitlv2widget.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
32
ground/openpilotgcs/src/plugins/hitlv2/plugin.pro
Normal file
32
ground/openpilotgcs/src/plugins/hitlv2/plugin.pro
Normal file
@ -0,0 +1,32 @@
|
||||
TEMPLATE = lib
|
||||
TARGET = HITLv2
|
||||
QT += network
|
||||
|
||||
include(../../openpilotgcsplugin.pri)
|
||||
include(hitlv2_dependencies.pri)
|
||||
|
||||
HEADERS += \
|
||||
aerosimrc.h \
|
||||
hitlv2configuration.h \
|
||||
hitlv2factory.h \
|
||||
hitlv2gadget.h \
|
||||
hitlv2optionspage.h \
|
||||
hitlv2plugin.h \
|
||||
hitlv2widget.h \
|
||||
simulatorv2.h
|
||||
|
||||
SOURCES += \
|
||||
aerosimrc.cpp \
|
||||
hitlv2configuration.cpp \
|
||||
hitlv2factory.cpp \
|
||||
hitlv2gadget.cpp \
|
||||
hitlv2optionspage.cpp \
|
||||
hitlv2plugin.cpp \
|
||||
hitlv2widget.cpp \
|
||||
simulatorv2.cpp
|
||||
|
||||
FORMS += \
|
||||
hitlv2optionspage.ui \
|
||||
hitlv2widget.ui
|
||||
|
||||
OTHER_FILES += hitlv2.pluginspec
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file simulator.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file simulatorv2.cpp
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -1,13 +1,13 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
*
|
||||
* @file simulator.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @file simulatorv2.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2012.
|
||||
* @addtogroup GCSPlugins GCS Plugins
|
||||
* @{
|
||||
* @addtogroup HITLPlugin HITL Plugin
|
||||
* @addtogroup HITLPlugin HITLv2 Plugin
|
||||
* @{
|
||||
* @brief The Hardware In The Loop plugin
|
||||
* @brief The Hardware In The Loop plugin version 2
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -247,14 +247,6 @@ FirmwareIAPObj::DataFields UAVObjectUtilManager::getFirmwareIap()
|
||||
if (!firmwareIap)
|
||||
return dummy;
|
||||
|
||||
// The code below will ask for the object update and wait for the updated to be received,
|
||||
// or the timeout of the timer, set to 1 second.
|
||||
QEventLoop loop;
|
||||
connect(firmwareIap, SIGNAL(objectUpdated(UAVObject*)), &loop, SLOT(quit()));
|
||||
QTimer::singleShot(1000, &loop, SLOT(quit())); // Create a timeout
|
||||
firmwareIap->requestUpdate();
|
||||
loop.exec();
|
||||
|
||||
return firmwareIap->getData();
|
||||
}
|
||||
|
||||
|
@ -388,6 +388,11 @@ void Telemetry::processObjectQueue()
|
||||
UAVObject::UpdateMode updateMode = UAVObject::GetGcsTelemetryUpdateMode(metadata);
|
||||
if ( ( objInfo.event != EV_UNPACKED ) && ( ( objInfo.event != EV_UPDATED_PERIODIC ) || ( updateMode != UAVObject::UPDATEMODE_THROTTLED ) ) )
|
||||
{
|
||||
QMap<quint32, ObjectTransactionInfo*>::iterator itr = transMap.find(objInfo.obj->getObjID());
|
||||
if ( itr != transMap.end() ) {
|
||||
qDebug() << "!!!!!! Making request for an object: " << objInfo.obj->getName() << " for which a request is already in progress!!!!!!";
|
||||
return;
|
||||
}
|
||||
UAVObject::Metadata metadata = objInfo.obj->getMetadata();
|
||||
ObjectTransactionInfo *transInfo = new ObjectTransactionInfo(this);
|
||||
transInfo->obj = objInfo.obj;
|
||||
|
@ -33,7 +33,7 @@ It is expected that you have the following tools installed into the listed
|
||||
locations (but any other locations are fine as well):
|
||||
|
||||
- Python in C:\Python27
|
||||
- QtSDK in C:\Qt\2010.05 or C:\QtSDK (depending on SDK version)
|
||||
- QtSDK in C:\QtSDK (depending on SDK version)
|
||||
- CodeSourcery G++ in %ProgramFiles%\CodeSourcery\Sourcery G++ Lite
|
||||
- msysGit in %ProgramFiles%\Git
|
||||
- Unicode NSIS in %ProgramFiles%\NSIS\Unicode
|
||||
@ -190,8 +190,8 @@ This set of scripts uses the MSYS package included into the msysGit
|
||||
distribution and MinGW make included into the QtSDK package.
|
||||
|
||||
The sh.cmd, shell_script.reg and this README.txt files were written
|
||||
by Oleg Semyonov (os-openpilot-org@os-propo.info) for the OpenPilot
|
||||
project and are licensed under CC-BY-SA terms:
|
||||
by Oleg Semyonov (os@openpilot.org) for the OpenPilot project and
|
||||
are licensed under CC-BY-SA terms:
|
||||
|
||||
http://creativecommons.org/licenses/by-sa/3.0/
|
||||
|
||||
|
@ -54,12 +54,8 @@ set NOT_FOUND=
|
||||
set PATH_DIRS=
|
||||
|
||||
call :which MSYSGIT "%ProgramFiles%\Git\bin" git.exe
|
||||
rem These two lines for qt-sdk-win-opensource-2010.05.exe:
|
||||
call :which QTMINGW "C:\Qt\2010.05\mingw\bin" mingw32-make.exe
|
||||
call :which QTSDK "C:\Qt\2010.05\qt\bin" qmake.exe
|
||||
rem These two lines for Qt_SDK_Win_offline_v1_1_1_en.exe:
|
||||
rem call :which QTMINGW "C:\QtSDK\mingw\bin" mingw32-make.exe
|
||||
rem call :which QTSDK "C:\QtSDK\Desktop\Qt\4.7.3\mingw\bin" qmake.exe
|
||||
call :which QTMINGW "C:\QtSDK\mingw\bin" mingw32-make.exe
|
||||
call :which QTSDK "C:\QtSDK\Desktop\Qt\4.8.1\mingw\bin" qmake.exe
|
||||
call :which CODESOURCERY "%ProgramFiles%\CodeSourcery\Sourcery G++ Lite\bin" cs-make.exe
|
||||
call :which PYTHON "C:\Python27" python.exe
|
||||
call :which UNSIS "%ProgramFiles%\NSIS\Unicode" makensis.exe
|
||||
|
@ -42,7 +42,7 @@ DEB_PACKAGE_NAME := openpilot_$(VERSION_FULL)_$(DEB_PLATFORM)
|
||||
|
||||
linux_deb_package: deb_build gcs
|
||||
@echo $@ starting
|
||||
cd .. && dpkg-buildpackage -b
|
||||
cd .. && dpkg-buildpackage -b -us -uc
|
||||
$(V1)mv $(ROOT_DIR)/../$(DEB_PACKAGE_NAME).deb $(BUILD_DIR)
|
||||
$(V1)mv $(ROOT_DIR)/../$(DEB_PACKAGE_NAME).changes $(BUILD_DIR)
|
||||
$(V1)rm -rf $(DEB_BUILD_DIR)
|
||||
|
@ -38,6 +38,7 @@
|
||||
!define NSIS_DATA_TREE "."
|
||||
!define GCS_BUILD_TREE "..\..\build\ground\openpilotgcs"
|
||||
!define UAVO_SYNTH_TREE "..\..\build\uavobject-synthetics"
|
||||
!define AEROSIMRC_TREE "..\..\build\ground\AeroSIM-RC"
|
||||
|
||||
; Default installation folder
|
||||
InstallDir "$PROGRAMFILES\OpenPilot"
|
||||
@ -161,7 +162,7 @@ Section "Core files" InSecCore
|
||||
SectionEnd
|
||||
|
||||
; Copy GCS plugins
|
||||
Section "Plugins" InSecPlugins
|
||||
Section "-Plugins" InSecPlugins
|
||||
SectionIn RO
|
||||
SetOutPath "$INSTDIR\lib\openpilotgcs\plugins"
|
||||
File /r "${GCS_BUILD_TREE}\lib\openpilotgcs\plugins\*.dll"
|
||||
@ -169,7 +170,7 @@ Section "Plugins" InSecPlugins
|
||||
SectionEnd
|
||||
|
||||
; Copy GCS resources
|
||||
Section "Resources" InSecResources
|
||||
Section "-Resources" InSecResources
|
||||
SetOutPath "$INSTDIR\share\openpilotgcs\diagrams"
|
||||
File /r "${GCS_BUILD_TREE}\share\openpilotgcs\diagrams\*"
|
||||
SetOutPath "$INSTDIR\share\openpilotgcs\dials"
|
||||
@ -183,14 +184,14 @@ Section "Resources" InSecResources
|
||||
SectionEnd
|
||||
|
||||
; Copy Notify plugin sound files
|
||||
Section "Sound files" InSecSounds
|
||||
Section "-Sound files" InSecSounds
|
||||
SetOutPath "$INSTDIR\share\openpilotgcs\sounds"
|
||||
File /r "${GCS_BUILD_TREE}\share\openpilotgcs\sounds\*"
|
||||
SectionEnd
|
||||
|
||||
; Copy localization files
|
||||
; Disabled until GCS source is stable and properly localized
|
||||
Section "Localization" InSecLocalization
|
||||
Section "-Localization" InSecLocalization
|
||||
SetOutPath "$INSTDIR\share\openpilotgcs\translations"
|
||||
; File /r "${GCS_BUILD_TREE}\share\openpilotgcs\translations\openpilotgcs_*.qm"
|
||||
File /r "${GCS_BUILD_TREE}\share\openpilotgcs\translations\qt_*.qm"
|
||||
@ -229,6 +230,12 @@ Section "CDC driver" InSecInstallDrivers
|
||||
ExecWait '"$PLUGINSDIR\dpinst.exe" /lm /path "$INSTDIR\drivers"'
|
||||
SectionEnd
|
||||
|
||||
; AeroSimRC plugin files
|
||||
Section "AeroSimRC plugin" InSecAeroSimRC
|
||||
SetOutPath "$INSTDIR\misc\AeroSIM-RC"
|
||||
File /r "${AEROSIMRC_TREE}\*"
|
||||
SectionEnd
|
||||
|
||||
Section "Shortcuts" InSecShortcuts
|
||||
; Create desktop and start menu shortcuts
|
||||
SetOutPath "$INSTDIR"
|
||||
@ -277,6 +284,7 @@ SectionEnd
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${InSecUtilities} $(DESC_InSecUtilities)
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${InSecDrivers} $(DESC_InSecDrivers)
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${InSecInstallDrivers} $(DESC_InSecInstallDrivers)
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${InSecAeroSimRC} $(DESC_InSecAeroSimRC)
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${InSecShortcuts} $(DESC_InSecShortcuts)
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
||||
|
||||
@ -301,6 +309,7 @@ Section "un.OpenPilot GCS" UnSecProgram
|
||||
RMDir /r /rebootok "$INSTDIR\firmware"
|
||||
RMDir /r /rebootok "$INSTDIR\utilities"
|
||||
RMDir /r /rebootok "$INSTDIR\drivers"
|
||||
RMDir /r /rebootok "$INSTDIR\misc"
|
||||
Delete /rebootok "$INSTDIR\HISTORY.txt"
|
||||
Delete /rebootok "$INSTDIR\Uninstall.exe"
|
||||
|
||||
|
@ -33,7 +33,8 @@
|
||||
LangString DESC_InSecFirmware ${LANG_GERMAN} "OpenPilot firmware binaries."
|
||||
LangString DESC_InSecUtilities ${LANG_GERMAN} "OpenPilot Dienstprogramme (Matlab Log Parser)."
|
||||
LangString DESC_InSecDrivers ${LANG_GERMAN} "OpenPilot Hardware Treiberdateien (optionaler OpenPilot CDC Treiber)."
|
||||
LangString DESC_InSecInstallDrivers ${LANG_GERMAN} "Installiere OpenPilot CDC Treiber (optional)."
|
||||
LangString DESC_InSecInstallDrivers ${LANG_GERMAN} "OpenPilot CDC Treiber (optional)."
|
||||
LangString DESC_InSecAeroSimRC ${LANG_GERMAN} "AeroSimRC plugin files with sample configuration."
|
||||
LangString DESC_InSecShortcuts ${LANG_GERMAN} "Installiere Verknüpfungen unter Startmenü->Anwendungen."
|
||||
|
||||
;--------------------------------
|
||||
|
@ -33,7 +33,8 @@
|
||||
LangString DESC_InSecFirmware ${LANG_ENGLISH} "OpenPilot firmware binaries."
|
||||
LangString DESC_InSecUtilities ${LANG_ENGLISH} "OpenPilot utilities (Matlab log parser)."
|
||||
LangString DESC_InSecDrivers ${LANG_ENGLISH} "OpenPilot hardware driver files (optional OpenPilot CDC driver)."
|
||||
LangString DESC_InSecInstallDrivers ${LANG_ENGLISH} "Install OpenPilot CDC driver (optional)."
|
||||
LangString DESC_InSecInstallDrivers ${LANG_ENGLISH} "Optional OpenPilot CDC driver (virtual USB COM port)."
|
||||
LangString DESC_InSecAeroSimRC ${LANG_ENGLISH} "AeroSimRC plugin files with sample configuration."
|
||||
LangString DESC_InSecShortcuts ${LANG_ENGLISH} "Install application start menu shortcuts."
|
||||
|
||||
;--------------------------------
|
||||
|
@ -33,7 +33,8 @@
|
||||
LangString DESC_InSecFirmware ${LANG_SPANISH} "OpenPilot firmware binaries."
|
||||
LangString DESC_InSecUtilities ${LANG_SPANISH} "OpenPilot utilities (Matlab log parser)."
|
||||
LangString DESC_InSecDrivers ${LANG_SPANISH} "OpenPilot hardware driver files (optional OpenPilot CDC driver)."
|
||||
LangString DESC_InSecInstallDrivers ${LANG_SPANISH} "Install OpenPilot CDC driver (optional)."
|
||||
LangString DESC_InSecInstallDrivers ${LANG_SPANISH} "Optional OpenPilot CDC driver (virtual USB COM port)."
|
||||
LangString DESC_InSecAeroSimRC ${LANG_SPANISH} "AeroSimRC plugin files with sample configuration."
|
||||
LangString DESC_InSecShortcuts ${LANG_SPANISH} "Instalar accesos directos de la aplicación (menú inicio y escritorio)."
|
||||
|
||||
;--------------------------------
|
||||
|
@ -33,7 +33,8 @@
|
||||
LangString DESC_InSecFirmware ${LANG_FRENCH} "OpenPilot firmware binaries."
|
||||
LangString DESC_InSecUtilities ${LANG_FRENCH} "OpenPilot utilities (Matlab log parser)."
|
||||
LangString DESC_InSecDrivers ${LANG_FRENCH} "OpenPilot hardware driver files (optional OpenPilot CDC driver)."
|
||||
LangString DESC_InSecInstallDrivers ${LANG_FRENCH} "Install OpenPilot CDC driver (optional)."
|
||||
LangString DESC_InSecInstallDrivers ${LANG_FRENCH} "Optional OpenPilot CDC driver (virtual USB COM port)."
|
||||
LangString DESC_InSecAeroSimRC ${LANG_FRENCH} "AeroSimRC plugin files with sample configuration."
|
||||
LangString DESC_InSecShortcuts ${LANG_FRENCH} "Installer les raccourcis dans le menu démarrer."
|
||||
|
||||
;--------------------------------
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user