migrated to hidapi-1.1.jar now libraries are located inside hidapi-1.1.jar also library can load them

Esse commit está contido em:
Denis Shmyga
2012-08-09 00:50:13 +03:00
commit a179dc0bec
87 arquivos alterados com 9534 adições e 0 exclusões
+10
Ver Arquivo
@@ -0,0 +1,10 @@
syntax:glob
*~
controltower/.settings/*
controltower/target/*
controltower/.classpath
controltower/.project
javadrone-api/.settings/*
javadrone-api/target/*
javadrone-api/.classpath
javadrone-api/.project
+93
Ver Arquivo
@@ -0,0 +1,93 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.codeminders</groupId>
<artifactId>javadrone</artifactId>
<version>${currentVersion}</version>
</parent>
<artifactId>controltower</artifactId>
<name>controltower</name>
<description>Demo navigation program using this API </description>
<build>
<finalName>controltower</finalName>
<resources>
<resource>
<directory>src/resources</directory>
</resource>
<resource>
<directory>lib</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<inherited>true</inherited>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.codeminders.controltower.ControlTower</mainClass>
<packageName>com.codeminders</packageName>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.codeminders.controltower.ControlTower</mainClass>
</manifest>
<manifestEntries>
<Built-By>Codeminders</Built-By>
</manifestEntries>
</archive>
<descriptors>
<descriptor>src/main/assembly/src.xml</descriptor>
</descriptors>
<finalName>${artifactId}-full-${currentVersion}</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.codeminders</groupId>
<artifactId>javadrone-api</artifactId>
<version>${currentVersion}</version>
</dependency>
<dependency>
<groupId>eu.hansolo</groupId>
<artifactId>SteelSeries</artifactId>
<version>3.9.2</version>
</dependency>
</dependencies>
</project>
+15
Ver Arquivo
@@ -0,0 +1,15 @@
<assembly>
<id>dist</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
@@ -0,0 +1,302 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="opaque" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,-64,0,0,2,-28"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel1">
<Properties>
<Property name="opaque" type="boolean" value="false"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="eu.hansolo.steelseries.extras.Indicator" name="indicator1">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="battery low"/>
<Property name="frame3dEffectVisible" type="boolean" value="true"/>
<Property name="symbolType" type="eu.hansolo.steelseries.tools.SymbolType" editor="org.netbeans.modules.form.editors.EnumEditor">
<Value id="BATTERY"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="50" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="50" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
<Container class="eu.hansolo.steelseries.extras.Indicator" name="indicator4">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="gyrometers down"/>
<Property name="frame3dEffectVisible" type="boolean" value="true"/>
<Property name="symbolType" type="eu.hansolo.steelseries.tools.SymbolType" editor="org.netbeans.modules.form.editors.EnumEditor">
<Value id="BREAK"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="50" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="50" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Container>
<Container class="eu.hansolo.steelseries.extras.Horizon" name="horizon1">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="artificial horizon"/>
<Property name="frame3dEffectVisible" type="boolean" value="true"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[60, 60]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="2" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="-20" ipadY="-20" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="180" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="180" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
<Container class="eu.hansolo.steelseries.extras.AirCompass" name="airCompass1">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="plane compass"/>
<Property name="frame3dEffectVisible" type="boolean" value="true"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[60, 60]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="3" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="-20" ipadY="-20" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="180" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="180" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
<Container class="eu.hansolo.steelseries.extras.Altimeter" name="altimeter1">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="altimeter"/>
<Property name="frame3dEffectVisible" type="boolean" value="true"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[60, 60]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="4" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="-60" ipadY="-60" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="62" max="-2" attributes="0"/>
<Component id="led1" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="62" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace pref="89" max="32767" attributes="0"/>
<Component id="led1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="35" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="eu.hansolo.steelseries.extras.Led" name="led1">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="16" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="16" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="jPanel2">
<Properties>
<Property name="opaque" type="boolean" value="false"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="5" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="eu.hansolo.steelseries.extras.Indicator" name="indicator2">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="emergency (click to reset)"/>
<Property name="frame3dEffectVisible" type="boolean" value="true"/>
<Property name="symbolType" type="eu.hansolo.steelseries.tools.SymbolType" editor="org.netbeans.modules.form.editors.EnumEditor">
<Value id="ATTENTION"/>
</Property>
</Properties>
<Events>
<EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="resetDrone"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="50" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="50" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
<Container class="eu.hansolo.steelseries.extras.Indicator" name="indicator3">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="engine problem"/>
<Property name="frame3dEffectVisible" type="boolean" value="true"/>
<Property name="symbolType" type="eu.hansolo.steelseries.tools.SymbolType" editor="org.netbeans.modules.form.editors.EnumEditor">
<Value id="ENGINE"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="50" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="50" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Container>
<Container class="eu.hansolo.steelseries.gauges.Radial1Vertical" name="batteryGraph">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="battery status"/>
<Property name="frame3dEffectVisible" type="boolean" value="true"/>
<Property name="threshold" type="double" value="110.0"/>
<Property name="title" type="java.lang.String" value="Battery"/>
<Property name="trackStartColor" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="trackStopColor" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="ff" red="0" type="rgb"/>
</Property>
<Property name="trackVisible" type="boolean" value="true"/>
<Property name="unitString" type="java.lang.String" value="%"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="-60" ipadY="-60" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="140" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="140" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,358 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/*
* BottomGaugePanel.java
*
* Created on 23.05.2011, 14:53:56
*/
package com.codeminders.controltower;
import com.codeminders.ardrone.ARDrone;
import com.codeminders.ardrone.NavData;
import com.codeminders.ardrone.NavDataListener;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference;
import javax.imageio.ImageIO;
import org.apache.log4j.Logger;
/**
*
* @author normenhansen
*/
@SuppressWarnings("serial")
public class BottomGaugePanel extends javax.swing.JPanel implements NavDataListener {
private BufferedImage commImage;
private AtomicReference<ARDrone> drone = new AtomicReference<ARDrone>();
/** Creates new form BottomGaugePanel */
public BottomGaugePanel() {
initComponents();
try {
commImage = ImageIO.read(getClass().getResourceAsStream("/com/codeminders/controltower/images/gaugeback_bottom2.png"));
} catch (IOException ex) {
Logger.getLogger(ControlTower.class.getName()).error("{0}", ex);
}
}
public void setDrone(ARDrone drone) {
this.drone.set(drone);
drone.addNavDataListener(this);
}
private void updateGauges(final NavData data) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
horizon1.setPitch(data.getPitch() * -1);
horizon1.setRoll(data.getRoll());
altimeter1.setValue(data.getAltitude() * 1000);
airCompass1.setValue(data.getYaw());
batteryGraph.setValue(data.getBattery());
if (data.isBatteryTooLow()) {
batteryGraph.setThreshold(0);
batteryGraph.setLedBlinking(true);
indicator1.setOn(true);
} else {
batteryGraph.setThreshold(110);
batteryGraph.setLedBlinking(false);
indicator1.setOn(false);
}
if (data.isUltrasonicSensorDeaf()) {
led1.setLedBlinking(true);
} else {
led1.setLedBlinking(false);
}
if (data.isEmergency()) {
indicator2.setOn(true);
} else {
indicator2.setOn(false);
}
if (data.isMotorsDown()) {
indicator3.setOn(true);
} else {
indicator3.setOn(false);
}
if (data.isGyrometersDown()) {
indicator4.setOn(true);
} else {
indicator4.setOn(false);
}
}
});
}
@Override
public void navDataReceived(NavData nd) {
updateGauges(nd);
}
@Override
protected void paintComponent(Graphics g) {
g.drawImage(commImage, 0, 0, getWidth(), getHeight(), null);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
jPanel1 = new javax.swing.JPanel();
indicator1 = new eu.hansolo.steelseries.extras.Indicator();
indicator4 = new eu.hansolo.steelseries.extras.Indicator();
horizon1 = new eu.hansolo.steelseries.extras.Horizon();
airCompass1 = new eu.hansolo.steelseries.extras.AirCompass();
altimeter1 = new eu.hansolo.steelseries.extras.Altimeter();
led1 = new eu.hansolo.steelseries.extras.Led();
jPanel2 = new javax.swing.JPanel();
indicator2 = new eu.hansolo.steelseries.extras.Indicator();
indicator3 = new eu.hansolo.steelseries.extras.Indicator();
batteryGraph = new eu.hansolo.steelseries.gauges.Radial1Vertical();
setOpaque(false);
setLayout(new java.awt.GridBagLayout());
jPanel1.setOpaque(false);
jPanel1.setLayout(new java.awt.GridBagLayout());
indicator1.setToolTipText("battery low");
indicator1.setFrame3dEffectVisible(true);
indicator1.setSymbolType(eu.hansolo.steelseries.tools.SymbolType.BATTERY);
javax.swing.GroupLayout indicator1Layout = new javax.swing.GroupLayout(indicator1);
indicator1.setLayout(indicator1Layout);
indicator1Layout.setHorizontalGroup(
indicator1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 50, Short.MAX_VALUE)
);
indicator1Layout.setVerticalGroup(
indicator1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 50, Short.MAX_VALUE)
);
jPanel1.add(indicator1, new java.awt.GridBagConstraints());
indicator4.setToolTipText("gyrometers down");
indicator4.setFrame3dEffectVisible(true);
indicator4.setSymbolType(eu.hansolo.steelseries.tools.SymbolType.BREAK);
javax.swing.GroupLayout indicator4Layout = new javax.swing.GroupLayout(indicator4);
indicator4.setLayout(indicator4Layout);
indicator4Layout.setHorizontalGroup(
indicator4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 50, Short.MAX_VALUE)
);
indicator4Layout.setVerticalGroup(
indicator4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 50, Short.MAX_VALUE)
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
jPanel1.add(indicator4, gridBagConstraints);
add(jPanel1, new java.awt.GridBagConstraints());
horizon1.setToolTipText("artificial horizon");
horizon1.setFrame3dEffectVisible(true);
horizon1.setMinimumSize(new java.awt.Dimension(60, 60));
javax.swing.GroupLayout horizon1Layout = new javax.swing.GroupLayout(horizon1);
horizon1.setLayout(horizon1Layout);
horizon1Layout.setHorizontalGroup(
horizon1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 180, Short.MAX_VALUE)
);
horizon1Layout.setVerticalGroup(
horizon1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 180, Short.MAX_VALUE)
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.ipadx = -20;
gridBagConstraints.ipady = -20;
add(horizon1, gridBagConstraints);
airCompass1.setToolTipText("plane compass");
airCompass1.setFrame3dEffectVisible(true);
airCompass1.setMinimumSize(new java.awt.Dimension(60, 60));
javax.swing.GroupLayout airCompass1Layout = new javax.swing.GroupLayout(airCompass1);
airCompass1.setLayout(airCompass1Layout);
airCompass1Layout.setHorizontalGroup(
airCompass1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 180, Short.MAX_VALUE)
);
airCompass1Layout.setVerticalGroup(
airCompass1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 180, Short.MAX_VALUE)
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.ipadx = -20;
gridBagConstraints.ipady = -20;
add(airCompass1, gridBagConstraints);
altimeter1.setToolTipText("altimeter");
altimeter1.setFrame3dEffectVisible(true);
altimeter1.setMinimumSize(new java.awt.Dimension(60, 60));
javax.swing.GroupLayout led1Layout = new javax.swing.GroupLayout(led1);
led1.setLayout(led1Layout);
led1Layout.setHorizontalGroup(
led1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 16, Short.MAX_VALUE)
);
led1Layout.setVerticalGroup(
led1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 16, Short.MAX_VALUE)
);
javax.swing.GroupLayout altimeter1Layout = new javax.swing.GroupLayout(altimeter1);
altimeter1.setLayout(altimeter1Layout);
altimeter1Layout.setHorizontalGroup(
altimeter1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(altimeter1Layout.createSequentialGroup()
.addGap(62, 62, 62)
.addComponent(led1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(62, Short.MAX_VALUE))
);
altimeter1Layout.setVerticalGroup(
altimeter1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, altimeter1Layout.createSequentialGroup()
.addContainerGap(89, Short.MAX_VALUE)
.addComponent(led1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(35, 35, 35))
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 4;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.ipadx = -60;
gridBagConstraints.ipady = -60;
add(altimeter1, gridBagConstraints);
jPanel2.setOpaque(false);
jPanel2.setLayout(new java.awt.GridBagLayout());
indicator2.setToolTipText("emergency (click to reset)");
indicator2.setFrame3dEffectVisible(true);
indicator2.setSymbolType(eu.hansolo.steelseries.tools.SymbolType.ATTENTION);
indicator2.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseReleased(java.awt.event.MouseEvent evt) {
resetDrone(evt);
}
});
javax.swing.GroupLayout indicator2Layout = new javax.swing.GroupLayout(indicator2);
indicator2.setLayout(indicator2Layout);
indicator2Layout.setHorizontalGroup(
indicator2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 50, Short.MAX_VALUE)
);
indicator2Layout.setVerticalGroup(
indicator2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 50, Short.MAX_VALUE)
);
jPanel2.add(indicator2, new java.awt.GridBagConstraints());
indicator3.setToolTipText("engine problem");
indicator3.setFrame3dEffectVisible(true);
indicator3.setSymbolType(eu.hansolo.steelseries.tools.SymbolType.ENGINE);
javax.swing.GroupLayout indicator3Layout = new javax.swing.GroupLayout(indicator3);
indicator3.setLayout(indicator3Layout);
indicator3Layout.setHorizontalGroup(
indicator3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 50, Short.MAX_VALUE)
);
indicator3Layout.setVerticalGroup(
indicator3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 50, Short.MAX_VALUE)
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
jPanel2.add(indicator3, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 5;
gridBagConstraints.gridy = 0;
add(jPanel2, gridBagConstraints);
batteryGraph.setToolTipText("battery status");
batteryGraph.setFrame3dEffectVisible(true);
batteryGraph.setThreshold(110.0);
batteryGraph.setTitle("Battery");
batteryGraph.setTrackStartColor(new java.awt.Color(255, 0, 0));
batteryGraph.setTrackStopColor(new java.awt.Color(0, 255, 0));
batteryGraph.setTrackVisible(true);
batteryGraph.setUnitString("%");
javax.swing.GroupLayout batteryGraphLayout = new javax.swing.GroupLayout(batteryGraph);
batteryGraph.setLayout(batteryGraphLayout);
batteryGraphLayout.setHorizontalGroup(
batteryGraphLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 140, Short.MAX_VALUE)
);
batteryGraphLayout.setVerticalGroup(
batteryGraphLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 140, Short.MAX_VALUE)
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.ipadx = -60;
gridBagConstraints.ipady = -60;
add(batteryGraph, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
private void resetDrone(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_resetDrone
ARDrone drone=this.drone.get();
if(drone!=null){
try {
drone.clearEmergencySignal();
} catch (IOException ex) {
Logger.getLogger(BottomGaugePanel.class.getName()).error("", ex);
}
}
}//GEN-LAST:event_resetDrone
// Variables declaration - do not modify//GEN-BEGIN:variables
private eu.hansolo.steelseries.extras.AirCompass airCompass1;
private eu.hansolo.steelseries.extras.Altimeter altimeter1;
private eu.hansolo.steelseries.gauges.Radial1Vertical batteryGraph;
private eu.hansolo.steelseries.extras.Horizon horizon1;
private eu.hansolo.steelseries.extras.Indicator indicator1;
private eu.hansolo.steelseries.extras.Indicator indicator2;
private eu.hansolo.steelseries.extras.Indicator indicator3;
private eu.hansolo.steelseries.extras.Indicator indicator4;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private eu.hansolo.steelseries.extras.Led led1;
// End of variables declaration//GEN-END:variables
}
@@ -0,0 +1,280 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" value="Controller Mapping"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel3" min="-2" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="85" max="32767" attributes="1"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jLabel5" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="valueList" alignment="0" pref="231" max="32767" attributes="0"/>
<Component id="commandList" alignment="0" pref="231" max="32767" attributes="0"/>
<Component id="jSeparator2" alignment="0" pref="231" max="32767" attributes="0"/>
<Component id="jToolBar1" alignment="1" pref="231" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="jLabel6" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="32" max="-2" attributes="0"/>
<Component id="delaySpinner" pref="133" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="durationSpinner" alignment="0" pref="133" max="32767" attributes="0"/>
<Component id="frequencySpinner" alignment="0" pref="133" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="jLabel5" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="commandList" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="valueList" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jLabel6" min="-2" max="-2" attributes="0"/>
<Component id="delaySpinner" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<Component id="durationSpinner" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<Component id="frequencySpinner" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Component id="jSeparator2" min="-2" pref="10" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jToolBar1" min="-2" pref="25" max="-2" attributes="0"/>
</Group>
<Component id="jScrollPane1" pref="227" max="32767" attributes="1"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="buttonList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
<StringArray count="5">
<StringItem index="0" value="Item 1"/>
<StringItem index="1" value="Item 2"/>
<StringItem index="2" value="Item 3"/>
<StringItem index="3" value="Item 4"/>
<StringItem index="4" value="Item 5"/>
</StringArray>
</Property>
</Properties>
<Events>
<EventHandler event="valueChanged" listener="javax.swing.event.ListSelectionListener" parameters="javax.swing.event.ListSelectionEvent" handler="listSelection"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JComboBox" name="commandList">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="4">
<StringItem index="0" value="Item 1"/>
<StringItem index="1" value="Item 2"/>
<StringItem index="2" value="Item 3"/>
<StringItem index="3" value="Item 4"/>
</StringArray>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="updateCommandSelection"/>
</Events>
</Component>
<Component class="javax.swing.JComboBox" name="valueList">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
<StringArray count="4">
<StringItem index="0" value="Item 1"/>
<StringItem index="1" value="Item 2"/>
<StringItem index="2" value="Item 3"/>
<StringItem index="3" value="Item 4"/>
</StringArray>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JSpinner" name="durationSpinner">
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="storeCommandz"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" value="Duration (ms)"/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel2">
<Properties>
<Property name="text" type="java.lang.String" value="Frequency"/>
</Properties>
</Component>
<Component class="javax.swing.JSpinner" name="frequencySpinner">
<Properties>
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
<SpinnerModel initial="0.0" numberType="java.lang.Float" stepSize="0.1" type="number"/>
</Property>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="storeCommandz"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="jLabel3">
<Properties>
<Property name="text" type="java.lang.String" value="Button"/>
</Properties>
</Component>
<Container class="javax.swing.JToolBar" name="jToolBar1">
<Properties>
<Property name="floatable" type="boolean" value="false"/>
<Property name="rollover" type="boolean" value="true"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
<SubComponents>
<Component class="javax.swing.JButton" name="jButton4">
<Properties>
<Property name="text" type="java.lang.String" value="prev"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton4ActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JPanel" name="jPanel1">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="46" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="21" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
<Component class="javax.swing.JLabel" name="jLabel4">
<Properties>
<Property name="text" type="java.lang.String" value="1"/>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="jPanel2">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="45" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="21" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
<Component class="javax.swing.JButton" name="jButton3">
<Properties>
<Property name="text" type="java.lang.String" value="next"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton3ActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator3">
</Component>
<Component class="javax.swing.JButton" name="storeButton">
<Properties>
<Property name="text" type="java.lang.String" value="store"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="storeButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="jLabel5">
<Properties>
<Property name="text" type="java.lang.String" value="Commands"/>
</Properties>
</Component>
<Component class="javax.swing.JSeparator" name="jSeparator2">
</Component>
<Component class="javax.swing.JLabel" name="jLabel6">
<Properties>
<Property name="text" type="java.lang.String" value="Delay (ms)"/>
</Properties>
</Component>
<Component class="javax.swing.JSpinner" name="delaySpinner">
<Properties>
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
<SpinnerModel initial="0" numberType="java.lang.Integer" stepSize="100" type="number"/>
</Property>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="storeCommandz"/>
</Events>
</Component>
</SubComponents>
</Form>
@@ -0,0 +1,508 @@
/*
* ControlConfig.java
*
* Created on 25.05.2011, 18:06:24
*/
package com.codeminders.controltower;
import com.codeminders.ardrone.ARDrone.Animation;
import com.codeminders.ardrone.ARDrone.LED;
import com.codeminders.controltower.config.AssignableControl;
import com.codeminders.controltower.config.AssignableControl.Command;
import com.codeminders.controltower.config.AssignableControl.ControllerButton;
import com.codeminders.controltower.config.ControlMap;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JFileChooser;
/**
*
* @author normenhansen
*/
@SuppressWarnings("serial")
public class ControlConfig extends javax.swing.JDialog {
private ControlMap map;
private List<AssignableControl> list;
private int index = 0;
/** Creates new form ControlConfig */
public ControlConfig(java.awt.Frame parent, boolean modal, ControlMap map) {
super(parent, modal);
this.map = map;
initComponents();
initButtonList();
initCommandList();
buttonList.setSelectedIndex(0);
}
/**
* Initializes the list of available buttons
*/
private void initButtonList() {
ControllerButton[] buttons = ControllerButton.values();
String[] str = new String[buttons.length];
for (int i = 0; i < buttons.length; i++) {
ControllerButton button = buttons[i];
str[i] = button.name();
}
buttonList.setListData(str);
}
/**
* Initializes the dropdown for available commands
*/
private void initCommandList() {
commandList.removeAllItems();
Command[] buttons = Command.values();
commandList.addItem("None");
for (int i = 0; i < buttons.length; i++) {
Command button = buttons[i];
commandList.addItem(button.name());
}
}
/**
* Sets to animation mode (enable duration)
*/
private void setAnimMode() {
valueList.removeAllItems();
Animation[] buttons = Animation.values();
for (int i = 0; i < buttons.length; i++) {
Animation button = buttons[i];
valueList.addItem(button.name());
}
valueList.setEnabled(true);
durationSpinner.setEnabled(true);
frequencySpinner.setEnabled(false);
}
/**
* Sets to LED mode (enable duration and frequency)
*/
private void setLEDMode() {
valueList.removeAllItems();
LED[] buttons = LED.values();
for (int i = 0; i < buttons.length; i++) {
LED button = buttons[i];
valueList.addItem(button.name());
}
valueList.setEnabled(true);
durationSpinner.setEnabled(true);
frequencySpinner.setEnabled(true);
}
/**
* Sets to Default mode (disable duration and frequency)
*/
private void setDefaultMode() {
valueList.removeAllItems();
valueList.setEnabled(false);
durationSpinner.setEnabled(false);
frequencySpinner.setEnabled(false);
}
/**
* Switches the mode based on the command selection
*/
private void switchMode() {
if (commandList.getSelectedItem() == null || "None".equals((String) commandList.getSelectedItem())) {
setDefaultMode();
return;
}
String str = (String) commandList.getSelectedItem();
if (str == null) {
return;
}
Command command = Command.valueOf(str);
if (command == Command.PLAY_ANIMATION) {
setAnimMode();
} else if (command == Command.PLAY_LED) {
setLEDMode();
} else {
setDefaultMode();
}
}
/**
* Updates the UI elements based on the selected button / command index
*/
private void updateButtonSelection() {
String controlbutton = (String) buttonList.getSelectedValue();
if (controlbutton == null) {
resetView();
return;
}
list = map.getControls(ControllerButton.valueOf(controlbutton));
jLabel4.setText((index + 1) + "");
if (list == null) {
list = new LinkedList<AssignableControl>();
commandList.setSelectedIndex(0);
setDefaultMode();
return;
}
if (list.size() <= index) {
commandList.setSelectedIndex(0);
setDefaultMode();
return;
}
AssignableControl control = list.get(index);
commandList.setSelectedItem(control.getCommand().name());
if (control.getCommand() == Command.PLAY_ANIMATION) {
setAnimMode();
valueList.setSelectedItem(control.getAnim().name());
} else if (control.getCommand() == Command.PLAY_LED) {
setLEDMode();
valueList.setSelectedItem(control.getLed().name());
} else {
setDefaultMode();
}
durationSpinner.setValue(control.getDuration());
frequencySpinner.setValue(control.getFrequency());
delaySpinner.setValue(control.getDelay());
}
/**
* Stores the current settings configured in the UI in the command list
* for the selected button
*/
private void storeButtonCommands() {
AssignableControl control = null;
String controlString = (String) buttonList.getSelectedValue();
String commandString = (String) commandList.getSelectedItem();
if (controlString == null) {
return;
}
ControllerButton button = ControllerButton.valueOf(controlString);
if (button == null) {
return;
}
if ("None".equals(commandString)) {
if (list.size() > index) {
list.remove(index);
}
return;
}
Command command = Command.valueOf((String) commandList.getSelectedItem());
if (command == null) {
return;
}
switch(command){
case PLAY_ANIMATION:
Animation anim = Animation.valueOf((String) valueList.getSelectedItem());
control = new AssignableControl(button, anim, (Integer) delaySpinner.getValue(), (Integer) durationSpinner.getValue());
break;
case PLAY_LED:
LED led = LED.valueOf((String) valueList.getSelectedItem());
float freq = frequencySpinner.getValue() instanceof Float ? (Float) frequencySpinner.getValue() : (Integer) frequencySpinner.getValue();
control = new AssignableControl(button, led, (Integer) delaySpinner.getValue(), freq, (Integer) durationSpinner.getValue());
break;
case TAKE_SNAPSHOT:
case RECORD_VIDEO:
control = new AssignableControl(button, command, (Integer) delaySpinner.getValue(), getFile());
break;
default:
control = new AssignableControl(button, command, (Integer) delaySpinner.getValue());
break;
}
list.add(index, control);
if (list.size() > index + 1) {
list.remove(index + 1);
}
map.setControls(button, list);
}
private File getFile() {
final JFileChooser fc = new JFileChooser();
fc.setDialogTitle("Select folder to store data");
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int returnVal = fc.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
return fc.getSelectedFile();
//This is where a real application would open the file.
} else {
return new File("." + File.separator);
}
}
/**
* Resets the UI display
*/
private void resetView() {
setDefaultMode();
index = 0;
jLabel4.setText("1");
commandList.setSelectedIndex(0);
durationSpinner.setValue(0);
frequencySpinner.setValue(0);
delaySpinner.setValue(0);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
buttonList = new javax.swing.JList();
commandList = new javax.swing.JComboBox();
valueList = new javax.swing.JComboBox();
durationSpinner = new javax.swing.JSpinner();
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
frequencySpinner = new javax.swing.JSpinner();
jLabel3 = new javax.swing.JLabel();
jToolBar1 = new javax.swing.JToolBar();
jButton4 = new javax.swing.JButton();
jPanel1 = new javax.swing.JPanel();
jLabel4 = new javax.swing.JLabel();
jPanel2 = new javax.swing.JPanel();
jButton3 = new javax.swing.JButton();
jSeparator3 = new javax.swing.JToolBar.Separator();
storeButton = new javax.swing.JButton();
jLabel5 = new javax.swing.JLabel();
jSeparator2 = new javax.swing.JSeparator();
jLabel6 = new javax.swing.JLabel();
delaySpinner = new javax.swing.JSpinner();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("Controller Mapping");
buttonList.setModel(new javax.swing.AbstractListModel() {
String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
public int getSize() { return strings.length; }
public Object getElementAt(int i) { return strings[i]; }
});
buttonList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
listSelection(evt);
}
});
jScrollPane1.setViewportView(buttonList);
commandList.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
commandList.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
updateCommandSelection(evt);
}
});
valueList.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
durationSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
storeCommandz(evt);
}
});
jLabel1.setText("Duration (ms)");
jLabel2.setText("Frequency");
frequencySpinner.setModel(new javax.swing.SpinnerNumberModel(Float.valueOf(0.0f), null, null, Float.valueOf(0.1f)));
frequencySpinner.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
storeCommandz(evt);
}
});
jLabel3.setText("Button");
jToolBar1.setFloatable(false);
jToolBar1.setRollover(true);
jButton4.setText("prev");
jButton4.setFocusable(false);
jButton4.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
jButton4.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jButton4.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton4ActionPerformed(evt);
}
});
jToolBar1.add(jButton4);
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 46, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 21, Short.MAX_VALUE)
);
jToolBar1.add(jPanel1);
jLabel4.setText("1");
jToolBar1.add(jLabel4);
javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
jPanel2.setLayout(jPanel2Layout);
jPanel2Layout.setHorizontalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 45, Short.MAX_VALUE)
);
jPanel2Layout.setVerticalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 21, Short.MAX_VALUE)
);
jToolBar1.add(jPanel2);
jButton3.setText("next");
jButton3.setFocusable(false);
jButton3.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
jButton3.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton3ActionPerformed(evt);
}
});
jToolBar1.add(jButton3);
jToolBar1.add(jSeparator3);
storeButton.setText("store");
storeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
storeButtonActionPerformed(evt);
}
});
jToolBar1.add(storeButton);
jLabel5.setText("Commands");
jLabel6.setText("Delay (ms)");
delaySpinner.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(0), null, null, Integer.valueOf(100)));
delaySpinner.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
storeCommandz(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel3)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jLabel5, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(valueList, javax.swing.GroupLayout.Alignment.LEADING, 0, 231, Short.MAX_VALUE)
.addComponent(commandList, javax.swing.GroupLayout.Alignment.LEADING, 0, 231, Short.MAX_VALUE)
.addComponent(jSeparator2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 231, Short.MAX_VALUE)
.addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 231, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(jLabel6)
.addGap(32, 32, 32)
.addComponent(delaySpinner, javax.swing.GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel1)
.addComponent(jLabel2))
.addGap(12, 12, 12)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(durationSpinner, javax.swing.GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE)
.addComponent(frequencySpinner, javax.swing.GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE))))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel5)
.addComponent(jLabel3))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(commandList, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(valueList, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jLabel6)
.addComponent(delaySpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jLabel1)
.addComponent(durationSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jLabel2)
.addComponent(frequencySpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 227, Short.MAX_VALUE))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void listSelection(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_listSelection
index = 0;
updateButtonSelection();
}//GEN-LAST:event_listSelection
private void updateCommandSelection(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_updateCommandSelection
switchMode();
}//GEN-LAST:event_updateCommandSelection
private void storeCommandz(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_storeCommandz
// storeButtonCommands();
}//GEN-LAST:event_storeCommandz
private void storeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_storeButtonActionPerformed
storeButtonCommands();
}//GEN-LAST:event_storeButtonActionPerformed
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton4ActionPerformed
if (index > 0) {
index--;
updateButtonSelection();
}
}//GEN-LAST:event_jButton4ActionPerformed
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed
if (index < list.size()) {
index++;
updateButtonSelection();
}
}//GEN-LAST:event_jButton3ActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JList buttonList;
private javax.swing.JComboBox commandList;
private javax.swing.JSpinner delaySpinner;
private javax.swing.JSpinner durationSpinner;
private javax.swing.JSpinner frequencySpinner;
private javax.swing.JButton jButton3;
private javax.swing.JButton jButton4;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JLabel jLabel5;
private javax.swing.JLabel jLabel6;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JSeparator jSeparator2;
private javax.swing.JToolBar.Separator jSeparator3;
private javax.swing.JToolBar jToolBar1;
private javax.swing.JButton storeButton;
private javax.swing.JComboBox valueList;
// End of variables declaration//GEN-END:variables
}
@@ -0,0 +1,208 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="3"/>
<Property name="title" type="java.lang.String" value="Control Tower"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jToolBar1" alignment="0" pref="800" max="32767" attributes="1"/>
<Component id="videoPanel" alignment="0" pref="800" max="32767" attributes="1"/>
<Component id="jPanel2" alignment="0" pref="800" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="videoPanel" pref="508" max="32767" attributes="1"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jPanel2" min="-2" pref="209" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jToolBar1" min="-2" pref="25" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JToolBar" name="jToolBar1">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.BevelBorderInfo">
<BevelBorder/>
</Border>
</Property>
<Property name="floatable" type="boolean" value="false"/>
<Property name="rollover" type="boolean" value="true"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
<SubComponents>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator5">
</Component>
<Component class="javax.swing.JLabel" name="droneStatus">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" id="red" palette="1" red="ff" type="palette"/>
</Property>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/com/codeminders/controltower/images/drone_off.gif"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value="drone status (lit = connected)"/>
</Properties>
<Events>
<EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="droneStatusMouseReleased"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="batteryStatus">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Lucida Grande" size="10" style="1"/>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" id="red" palette="1" red="ff" type="palette"/>
</Property>
<Property name="text" type="java.lang.String" value="0%"/>
</Properties>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator1">
</Component>
<Component class="javax.swing.JLabel" name="joystickControllerStatus">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" id="red" palette="1" red="ff" type="palette"/>
</Property>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/com/codeminders/controltower/images/controller_off.png"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value="controller status (green = available)"/>
</Properties>
<Events>
<EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="joystickControllerStatusMouseReleased"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="keyboardControllerStatus">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" id="red" palette="1" red="ff" type="palette"/>
</Property>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/com/codeminders/controltower/images/keyboard_off.png"/>
</Property>
<Property name="toolTipText" type="java.lang.String" value="keyboard status (green = available)"/>
</Properties>
<Events>
<EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="keyboardControllerStatusMouseReleased"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="flipSticksCheckbox">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Lucida Grande" size="10" style="0"/>
</Property>
<Property name="text" type="java.lang.String" value="flip sticks"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="flipSticksCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="mappingButton">
<Properties>
<Property name="text" type="java.lang.String" value="mapping"/>
<Property name="toolTipText" type="java.lang.String" value="map controller buttons"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="mappingButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator3">
</Component>
<Container class="javax.swing.JPanel" name="jPanel1">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="384" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="21" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator7">
</Component>
<Component class="javax.swing.JButton" name="instrumentButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/com/codeminders/controltower/images/instruments.gif"/>
</Property>
<Property name="text" type="java.lang.String" value="instruments"/>
<Property name="toolTipText" type="java.lang.String" value="toggle instruments"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="instrumentButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="configureButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/com/codeminders/controltower/images/objects_039.gif"/>
</Property>
<Property name="text" type="java.lang.String" value="tuning"/>
<Property name="toolTipText" type="java.lang.String" value="show drone tuning settings"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="4"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="configureButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator6">
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="videoPanel">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="66" green="66" red="66" type="rgb"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[320, 240]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="jPanel2">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,757 @@
/*
* ControlTower.java
*
* Created on 17.05.2011, 13:41:27
*/
package com.codeminders.controltower;
import java.awt.Color;
import java.awt.Dimension;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.prefs.Preferences;
import javax.swing.ImageIcon;
import org.apache.log4j.Logger;
import com.codeminders.ardrone.ARDrone;
import com.codeminders.ardrone.ARDrone.VideoChannel;
import com.codeminders.ardrone.DroneStatusChangeListener;
import com.codeminders.ardrone.NavData;
import com.codeminders.ardrone.NavDataListener;
import com.codeminders.ardrone.controllers.AfterGlowController;
import com.codeminders.ardrone.controllers.KeyboardController;
import com.codeminders.ardrone.controllers.PS3Controller;
import com.codeminders.ardrone.controllers.PS3ControllerState;
import com.codeminders.ardrone.controllers.PS3ControllerStateChange;
import com.codeminders.ardrone.controllers.SonyPS3Controller;
import com.codeminders.controltower.config.AssignableControl.ControllerButton;
import com.codeminders.controltower.config.ControlMap;
import com.codeminders.hidapi.ClassPathLibraryLoader;
import com.codeminders.hidapi.HIDDeviceInfo;
import com.codeminders.hidapi.HIDDeviceNotFoundException;
import com.codeminders.hidapi.HIDManager;
/**
* The central class that represents the main window and also manages the
* drone update loop.
*
* @author normenhansen
*/
@SuppressWarnings("serial")
public class ControlTower extends javax.swing.JFrame implements DroneStatusChangeListener, NavDataListener
{
private static final long READ_UPDATE_DELAY_MS = 5L;
private static final long CONNECT_TIMEOUT = 8000L;
private static float CONTROL_THRESHOLD = 0.5f;
private final ImageIcon droneOn = new ImageIcon(
getClass().getResource("/com/codeminders/controltower/images/drone_on.gif"));
private final ImageIcon droneOff = new ImageIcon(
getClass().getResource("/com/codeminders/controltower/images/drone_off.gif"));
private final ImageIcon controllerOn = new ImageIcon(
getClass().getResource("/com/codeminders/controltower/images/controller_on.png"));
private final ImageIcon keyboradControllerOn = new ImageIcon(
getClass().getResource("/com/codeminders/controltower/images/keyboard_on.png"));
private final ImageIcon controllerOff = new ImageIcon(
getClass().getResource("/com/codeminders/controltower/images/controller_off.png"));
private final ImageIcon keyboradControllerOff = new ImageIcon(
getClass().getResource("/com/codeminders/controltower/images/keyboard_off.png"));
private final AtomicBoolean running = new AtomicBoolean(false);
private final AtomicBoolean flying = new AtomicBoolean(false);
private final AtomicBoolean flipSticks = new AtomicBoolean(false);
private final Preferences prefs = Preferences.userNodeForPackage(this.getClass());
private ARDrone drone;
private final AtomicReference<PS3Controller> dev = new AtomicReference<PS3Controller>();
private final VideoPanel video = new VideoPanel();
private final DroneConfig droneConfigWindow;
private final ControlConfig controlConfigWindow;
private final KeyboardControlConfig keyboardControlConfigWindow;
private final BottomGaugePanel gauges = new BottomGaugePanel();
private final ControlMap controlMap = new ControlMap();
private static boolean isHIDLibLoaded = false;
static
{
isHIDLibLoaded = ClassPathLibraryLoader.loadNativeHIDLibrary();
}
/**
* Creates new form ControlTower
*/
public ControlTower()
{
setAlwaysOnTop(true);
initComponents();
droneConfigWindow = new DroneConfig(this, true);
keyboardControlConfigWindow = new KeyboardControlConfig(this, true);
controlConfigWindow = new ControlConfig(this, true, controlMap);
videoPanel.add(video);
jPanel2.add(gauges);
initController();
initDrone();
flipSticks.set(prefs.getBoolean("FLIP_STICKS", false));
flipSticksCheckbox.setSelected(flipSticks.get());
}
private void initDrone()
{
try
{
drone = new ARDrone();
}
catch(UnknownHostException ex)
{
Logger.getLogger(ControlTower.class.getName()).error("Error creating drone object!", ex);
return;
}
droneConfigWindow.setDrone(drone);
gauges.setDrone(drone);
video.setDrone(drone);
drone.addStatusChangeListener(this);
drone.addNavDataListener(this);
}
/**
* Tries to find PS3 controller, else creates keyboard controller
*/
private void initController()
{
PS3Controller current = dev.get();
if(current != null)
{
try
{
current.close();
}
catch(IOException ex)
{
Logger.getLogger(ControlTower.class.getName()).error("", ex);
}
}
try
{
dev.set(findController());
}
catch(IOException ex)
{
Logger.getLogger(ControlTower.class.getName()).error("{0}", ex);
}
if(dev.get() == null)
{
System.err.println("No suitable controller found! Using keyboard");
dev.set(new KeyboardController(this));
updateControllerStatus(false);
}
else
{
System.err.println("Gamepad controller found");
updateControllerStatus(true);
}
}
private static PS3Controller findController() throws IOException
{
if(!isHIDLibLoaded)
return null;
HIDDeviceInfo[] devs = HIDManager.getInstance().listDevices();
if (null != devs) {
for(int i = 0; i < devs.length; i++)
{
System.out.println("" + devs[i]);
if(AfterGlowController.isA(devs[i]))
{
return new AfterGlowController(devs[i]);
}
if(SonyPS3Controller.isA(devs[i]))
{
return new SonyPS3Controller(devs[i]);
}
}
}
return null;
}
private void updateLoop()
{
if(running.get())
{
return;
}
running.set(true);
resetStatus();
try
{
drone.addStatusChangeListener(new DroneStatusChangeListener()
{
@Override
public void ready()
{
try
{
Logger.getLogger(getClass().getName()).debug("updateLoop::ready()");
System.err.println("Configure");
droneConfigWindow.updateDrone();
drone.selectVideoChannel(VideoChannel.HORIZONTAL_ONLY);
drone.setCombinedYawMode(true);
drone.trim();
}
catch(IOException e)
{
drone.changeToErrorState(e);
}
}
});
System.err.println("Connecting to the drone");
drone.connect();
drone.waitForReady(CONNECT_TIMEOUT);
drone.clearEmergencySignal();
System.err.println("Connected to the drone");
try
{
PS3ControllerState oldpad = null;
while(running.get())
{
PS3ControllerState pad = dev.get().read();
PS3ControllerStateChange pad_change = new PS3ControllerStateChange(oldpad, pad);
oldpad = pad;
if(pad_change.isStartChanged() && pad_change.isStart())
{
controlMap.sendCommand(drone, ControllerButton.START);
}
if(pad_change.isSelectChanged() && pad_change.isSelect())
{
controlMap.sendCommand(drone, ControllerButton.SELECT);
}
if(pad_change.isPSChanged() && pad_change.isPS())
{
controlMap.sendCommand(drone, ControllerButton.PS);
}
if(pad_change.isTriangleChanged() && pad_change.isTriangle())
{
controlMap.sendCommand(drone, ControllerButton.TRIANGLE);
}
if(pad_change.isCrossChanged() && pad_change.isCross())
{
controlMap.sendCommand(drone, ControllerButton.CROSS);
}
if(pad_change.isSquareChanged() && pad_change.isSquare())
{
controlMap.sendCommand(drone, ControllerButton.SQUARE);
}
if(pad_change.isCircleChanged() && pad_change.isCircle())
{
controlMap.sendCommand(drone, ControllerButton.CIRCLE);
}
if(pad_change.isL1Changed() && pad_change.isL1())
{
controlMap.sendCommand(drone, ControllerButton.L1);
}
if(pad_change.isR1Changed() && pad_change.isR1())
{
controlMap.sendCommand(drone, ControllerButton.R1);
}
if(pad_change.isL2Changed() && pad_change.isL2())
{
controlMap.sendCommand(drone, ControllerButton.L2);
}
if(pad_change.isR2Changed() && pad_change.isR2())
{
controlMap.sendCommand(drone, ControllerButton.R2);
}
if(flying.get())
{
// Detecting if we need to move the drone
int leftX = pad.getLeftJoystickX();
int leftY = pad.getLeftJoystickY();
int rightX = pad.getRightJoystickX();
int rightY = pad.getRightJoystickY();
float left_right_tilt = 0f;
float front_back_tilt = 0f;
float vertical_speed = 0f;
float angular_speed = 0f;
if(Math.abs(((float) leftX) / 128f) > CONTROL_THRESHOLD)
{
left_right_tilt = ((float) leftX) / 128f;
}
if(Math.abs(((float) leftY) / 128f) > CONTROL_THRESHOLD)
{
front_back_tilt = ((float) leftY) / 128f;
}
if(Math.abs(((float) rightX) / 128f) > CONTROL_THRESHOLD)
{
angular_speed = ((float) rightX) / 128f;
}
if(Math.abs(-1 * ((float) rightY) / 128f) > CONTROL_THRESHOLD)
{
vertical_speed = -1 * ((float) rightY) / 128f;
}
if(left_right_tilt != 0 || front_back_tilt != 0 || vertical_speed != 0 || angular_speed != 0)
{
if(flipSticks.get())
{
drone.move(angular_speed, -1 * vertical_speed, -1 * front_back_tilt, left_right_tilt);
}
else
{
drone.move(left_right_tilt, front_back_tilt, vertical_speed, angular_speed);
}
}
else
{
drone.hover();
}
}
try
{
Thread.sleep(READ_UPDATE_DELAY_MS);
}
catch(InterruptedException e)
{
// Ignore
}
}
}
finally
{
drone.disconnect();
}
}
catch(HIDDeviceNotFoundException hex)
{
hex.printStackTrace();
}
catch(Throwable e)
{
e.printStackTrace();
}
resetStatus();
running.set(false);
}
private void startUpdateLoop()
{
Thread thread = new Thread(new Runnable()
{
@Override
public void run()
{
updateLoop();
}
});
thread.setName("ARDrone Control Loop");
thread.start();
}
/**
* Updates the drone status in the UI, queues command to AWT event dispatch thread
*
* @param available
*/
private void updateDroneStatus(final boolean available)
{
java.awt.EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
if(!available)
{
droneStatus.setForeground(Color.RED);
droneStatus.setIcon(droneOff);
}
else
{
droneStatus.setForeground(Color.GREEN);
droneStatus.setIcon(droneOn);
}
}
});
}
/**
* Updates the controller status in the UI, queues command to AWT event dispatch thread
*
* @param available
*/
private void updateControllerStatus(final boolean available)
{
java.awt.EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
if(!available)
{
joystickControllerStatus.setForeground(Color.RED);
joystickControllerStatus.setIcon(controllerOff);
keyboardControllerStatus.setForeground(Color.GREEN);
keyboardControllerStatus.setIcon(keyboradControllerOn);
}
else
{
joystickControllerStatus.setForeground(Color.GREEN);
joystickControllerStatus.setIcon(controllerOn);
keyboardControllerStatus.setForeground(Color.RED);
keyboardControllerStatus.setIcon(keyboradControllerOff);
}
}
});
}
/**
* Updates the battery status in the UI, queues command to AWT event dispatch thread
*
* @param value
*/
private void updateBatteryStatus(final int value)
{
java.awt.EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
batteryStatus.setText(value + "%");
if(value < 15)
{
batteryStatus.setForeground(Color.RED);
}
else if(value < 50)
{
batteryStatus.setForeground(Color.ORANGE);
}
else
{
batteryStatus.setForeground(Color.GREEN);
}
}
});
}
/**
* Resets the UI, queues command to AWT event dispatch thread
*
*/
private void resetStatus()
{
java.awt.EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
droneStatus.setForeground(Color.RED);
droneStatus.setIcon(droneOff);
batteryStatus.setForeground(Color.RED);
batteryStatus.setText("0%");
}
});
}
@Override
public void ready()
{
Logger.getLogger(getClass().getName()).debug("ready()");
updateDroneStatus(true);
}
@Override
public void navDataReceived(NavData nd)
{
Logger.getLogger(getClass().getName()).debug("navDataReceived()");
updateBatteryStatus(nd.getBattery());
this.flying.set(nd.isFlying());
}
public void setControlThreshold(float sens)
{
CONTROL_THRESHOLD = sens;
}
/**
* This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jToolBar1 = new javax.swing.JToolBar();
jSeparator5 = new javax.swing.JToolBar.Separator();
droneStatus = new javax.swing.JLabel();
batteryStatus = new javax.swing.JLabel();
jSeparator1 = new javax.swing.JToolBar.Separator();
joystickControllerStatus = new javax.swing.JLabel();
keyboardControllerStatus = new javax.swing.JLabel();
flipSticksCheckbox = new javax.swing.JCheckBox();
mappingButton = new javax.swing.JButton();
jSeparator3 = new javax.swing.JToolBar.Separator();
jPanel1 = new javax.swing.JPanel();
jSeparator7 = new javax.swing.JToolBar.Separator();
instrumentButton = new javax.swing.JButton();
configureButton = new javax.swing.JButton();
jSeparator6 = new javax.swing.JToolBar.Separator();
videoPanel = new javax.swing.JPanel();
jPanel2 = new javax.swing.JPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Control Tower");
jToolBar1.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
jToolBar1.setFloatable(false);
jToolBar1.setRollover(true);
jToolBar1.add(jSeparator5);
droneStatus.setForeground(java.awt.Color.red);
droneStatus.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/codeminders/controltower/images/drone_off.gif"))); // NOI18N
droneStatus.setToolTipText("drone status (lit = connected)");
droneStatus.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseReleased(java.awt.event.MouseEvent evt) {
droneStatusMouseReleased(evt);
}
});
jToolBar1.add(droneStatus);
batteryStatus.setFont(new java.awt.Font("Lucida Grande", 1, 10)); // NOI18N
batteryStatus.setForeground(java.awt.Color.red);
batteryStatus.setText("0%");
jToolBar1.add(batteryStatus);
jToolBar1.add(jSeparator1);
joystickControllerStatus.setForeground(java.awt.Color.red);
joystickControllerStatus.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/codeminders/controltower/images/controller_off.png"))); // NOI18N
joystickControllerStatus.setToolTipText("controller status (green = available)");
joystickControllerStatus.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseReleased(java.awt.event.MouseEvent evt) {
joystickControllerStatusMouseReleased(evt);
}
});
jToolBar1.add(joystickControllerStatus);
keyboardControllerStatus.setForeground(java.awt.Color.red);
keyboardControllerStatus.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/codeminders/controltower/images/keyboard_off.png"))); // NOI18N
keyboardControllerStatus.setToolTipText("keyboard status (green = available)");
keyboardControllerStatus.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseReleased(java.awt.event.MouseEvent evt) {
keyboardControllerStatusMouseReleased(evt);
}
});
jToolBar1.add(keyboardControllerStatus);
flipSticksCheckbox.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
flipSticksCheckbox.setText("flip sticks");
flipSticksCheckbox.setFocusable(false);
flipSticksCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
flipSticksCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
flipSticksCheckboxActionPerformed(evt);
}
});
jToolBar1.add(flipSticksCheckbox);
mappingButton.setText("mapping");
mappingButton.setToolTipText("map controller buttons");
mappingButton.setFocusable(false);
mappingButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
mappingButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
mappingButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
mappingButtonActionPerformed(evt);
}
});
jToolBar1.add(mappingButton);
jToolBar1.add(jSeparator3);
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 384, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 21, Short.MAX_VALUE)
);
jToolBar1.add(jPanel1);
jToolBar1.add(jSeparator7);
instrumentButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/codeminders/controltower/images/instruments.gif"))); // NOI18N
instrumentButton.setText("instruments");
instrumentButton.setToolTipText("toggle instruments");
instrumentButton.setFocusable(false);
instrumentButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
instrumentButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
instrumentButtonActionPerformed(evt);
}
});
jToolBar1.add(instrumentButton);
configureButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/codeminders/controltower/images/objects_039.gif"))); // NOI18N
configureButton.setText("tuning");
configureButton.setToolTipText("show drone tuning settings");
configureButton.setFocusable(false);
configureButton.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT);
configureButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
configureButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
configureButtonActionPerformed(evt);
}
});
jToolBar1.add(configureButton);
jToolBar1.add(jSeparator6);
videoPanel.setBackground(new java.awt.Color(102, 102, 102));
videoPanel.setPreferredSize(new java.awt.Dimension(320, 240));
videoPanel.setLayout(new javax.swing.BoxLayout(videoPanel, javax.swing.BoxLayout.LINE_AXIS));
jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.LINE_AXIS));
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 800, Short.MAX_VALUE)
.addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 800, Short.MAX_VALUE)
.addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, 800, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 508, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, 209, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void configureButtonActionPerformed(java.awt.event.ActionEvent evt)
{//GEN-FIRST:event_configureButtonActionPerformed
droneConfigWindow.setLocationRelativeTo(this);
droneConfigWindow.setVisible(true);
}//GEN-LAST:event_configureButtonActionPerformed
private void droneStatusMouseReleased(java.awt.event.MouseEvent evt)
{//GEN-FIRST:event_droneStatusMouseReleased
startUpdateLoop();
}//GEN-LAST:event_droneStatusMouseReleased
private void controllerStatusMouseReleased(java.awt.event.MouseEvent evt)
{//GEN-FIRST:event_controllerStatusMouseReleased
initController();
}//GEN-LAST:event_controllerStatusMouseReleased
private void instrumentButtonActionPerformed(java.awt.event.ActionEvent evt)
{//GEN-FIRST:event_instrumentButtonActionPerformed
Dimension dim = jPanel2.getSize();
if(dim.getHeight() > 0)
{
dim.setSize(dim.getWidth(), 0);
jPanel2.setPreferredSize(dim);
jPanel2.setSize(dim);
jPanel2.setVisible(false);
}
else
{
dim.setSize(dim.getWidth(), 210);
jPanel2.setPreferredSize(dim);
jPanel2.setSize(dim);
jPanel2.setVisible(true);
}
}//GEN-LAST:event_instrumentButtonActionPerformed
private void mappingButtonActionPerformed(java.awt.event.ActionEvent evt)
{//GEN-FIRST:event_mappingButtonActionPerformed
if (keyboardControllerStatus.getForeground() != Color.GREEN) {
controlConfigWindow.setLocationRelativeTo(this);
controlConfigWindow.setVisible(true);
} else {
keyboardControlConfigWindow.setLocationRelativeTo(this);
keyboardControlConfigWindow.setVisible(true);
}
}//GEN-LAST:event_mappingButtonActionPerformed
private void flipSticksCheckboxActionPerformed(java.awt.event.ActionEvent evt)
{//GEN-FIRST:event_flipSticksCheckboxActionPerformed
flipSticks.set(flipSticksCheckbox.isSelected());
prefs.putBoolean("FLIP_STICKS", flipSticks.get());
}//GEN-LAST:event_flipSticksCheckboxActionPerformed
private void keyboardControllerStatusMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_keyboardControllerStatusMouseReleased
initController();
}//GEN-LAST:event_keyboardControllerStatusMouseReleased
private void joystickControllerStatusMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_joystickControllerStatusMouseReleased
initController();
}//GEN-LAST:event_joystickControllerStatusMouseReleased
/**
* @param args the command line arguments
*/
public static void main(String args[])
{
final ControlTower tower = new ControlTower();
java.awt.EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
tower.setLocationRelativeTo(null);
tower.setVisible(true);
}
});
tower.startUpdateLoop();
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel batteryStatus;
private javax.swing.JButton configureButton;
private javax.swing.JLabel droneStatus;
private javax.swing.JCheckBox flipSticksCheckbox;
private javax.swing.JButton instrumentButton;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JToolBar.Separator jSeparator1;
private javax.swing.JToolBar.Separator jSeparator3;
private javax.swing.JToolBar.Separator jSeparator5;
private javax.swing.JToolBar.Separator jSeparator6;
private javax.swing.JToolBar.Separator jSeparator7;
private javax.swing.JToolBar jToolBar1;
private javax.swing.JLabel joystickControllerStatus;
private javax.swing.JLabel keyboardControllerStatus;
private javax.swing.JButton mappingButton;
private javax.swing.JPanel videoPanel;
// End of variables declaration//GEN-END:variables
}
@@ -0,0 +1,112 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" value="Configuration"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,-57,0,0,1,77"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
<Property name="columns" type="int" value="2"/>
<Property name="rows" type="int" value="6"/>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="maxAltitudeLabel">
<Properties>
<Property name="text" type="java.lang.String" value="Max Altitude"/>
</Properties>
</Component>
<Component class="javax.swing.JSlider" name="maxAltitude">
<Properties>
<Property name="maximum" type="int" value="10000"/>
<Property name="value" type="int" value="10000"/>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="updateAlt"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="maxAngleLabel">
<Properties>
<Property name="text" type="java.lang.String" value="Max Angle"/>
</Properties>
</Component>
<Component class="javax.swing.JSlider" name="maxAngle">
<Properties>
<Property name="value" type="int" value="20"/>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="updateAngle"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="maxSpeedLabel">
<Properties>
<Property name="text" type="java.lang.String" value="Vertical Speed"/>
</Properties>
</Component>
<Component class="javax.swing.JSlider" name="maxSpeed">
<Properties>
<Property name="maximum" type="int" value="3000"/>
<Property name="value" type="int" value="2000"/>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="updateSpeed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="maxYawLabel">
<Properties>
<Property name="text" type="java.lang.String" value="Rotation Speed"/>
</Properties>
</Component>
<Component class="javax.swing.JSlider" name="maxYaw">
<Properties>
<Property name="maximum" type="int" value="611"/>
<Property name="minimum" type="int" value="70"/>
<Property name="value" type="int" value="200"/>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="updateYaw"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="controllerDeadzoneLabel">
<Properties>
<Property name="text" type="java.lang.String" value="Controller Deadzone"/>
</Properties>
</Component>
<Component class="javax.swing.JSlider" name="controllerDeadzone">
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="updateDeadZone"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" value="Close"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="okButton">
<Properties>
<Property name="text" type="java.lang.String" value="Apply"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>
@@ -0,0 +1,235 @@
/*
* DroneConfig.java
*
* Created on 17.05.2011, 15:19:40
*/
package com.codeminders.controltower;
import com.codeminders.ardrone.ARDrone;
import java.io.IOException;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import org.apache.log4j.Logger;
/**
*
* @author normenhansen
*/
@SuppressWarnings("serial")
public class DroneConfig extends javax.swing.JDialog {
private ARDrone drone;
private ControlTower tower;
private Preferences prefs;
/** Creates new form DroneConfig */
public DroneConfig(ControlTower tower, boolean modal) {
super(tower, modal);
this.tower = tower;
prefs = Preferences.userNodeForPackage(this.getClass());
initComponents();
loadSettings();
}
private synchronized void saveSettings() {
prefs.putInt("control:altitude_max", maxAltitude.getValue());
prefs.putInt("control:euler_angle_max", maxAngle.getValue());
prefs.putInt("control:control_vz_max", maxSpeed.getValue());
prefs.putInt("control:control_yaw", maxYaw.getValue());
prefs.putInt("tower:controller_threshold", controllerDeadzone.getValue());
try {
prefs.flush();
} catch (BackingStoreException ex) {
Logger.getLogger(DroneConfig.class.getName()).error("Cannot save settings: {0}", ex);
}
}
private synchronized void loadSettings() {
maxAltitude.setValue(prefs.getInt("control:altitude_max", 10000));
maxAngle.setValue(prefs.getInt("control:euler_angle_max", 20));
maxSpeed.setValue(prefs.getInt("control:control_vz_max", 2000));
maxYaw.setValue(prefs.getInt("control:control_yaw", 200));
controllerDeadzone.setValue(prefs.getInt("tower:controller_threshold", 50));
updateAlt(null);
updateAngle(null);
updateSpeed(null);
updateYaw(null);
updateDeadZone(null);
}
public synchronized void setDrone(ARDrone drone) {
this.drone = drone;
}
public synchronized void updateDrone() {
if (drone == null) {
return;
}
try {
drone.setConfigOption("control:altitude_max", maxAltitude.getValue() + "");
drone.setConfigOption("control:euler_angle_max", (((float) maxAngle.getValue()) / 100.0f) + "");
drone.setConfigOption("control:control_vz_max", maxSpeed.getValue() + "");
drone.setConfigOption("control:control_yaw", (((float) maxYaw.getValue()) / 100.0f) + "");
tower.setControlThreshold(((float) controllerDeadzone.getValue()) / 100.0f);
} catch (IOException ex) {
Logger.getLogger(DroneConfig.class.getName()).error("Exception Setting data: {0}", ex);
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
maxAltitudeLabel = new javax.swing.JLabel();
maxAltitude = new javax.swing.JSlider();
maxAngleLabel = new javax.swing.JLabel();
maxAngle = new javax.swing.JSlider();
maxSpeedLabel = new javax.swing.JLabel();
maxSpeed = new javax.swing.JSlider();
maxYawLabel = new javax.swing.JLabel();
maxYaw = new javax.swing.JSlider();
controllerDeadzoneLabel = new javax.swing.JLabel();
controllerDeadzone = new javax.swing.JSlider();
cancelButton = new javax.swing.JButton();
okButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("Configuration");
getContentPane().setLayout(new java.awt.GridLayout(6, 2));
maxAltitudeLabel.setText("Max Altitude");
getContentPane().add(maxAltitudeLabel);
maxAltitude.setMaximum(10000);
maxAltitude.setValue(10000);
maxAltitude.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
updateAlt(evt);
}
});
getContentPane().add(maxAltitude);
maxAngleLabel.setText("Max Angle");
getContentPane().add(maxAngleLabel);
maxAngle.setValue(20);
maxAngle.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
updateAngle(evt);
}
});
getContentPane().add(maxAngle);
maxSpeedLabel.setText("Vertical Speed");
getContentPane().add(maxSpeedLabel);
maxSpeed.setMaximum(3000);
maxSpeed.setValue(2000);
maxSpeed.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
updateSpeed(evt);
}
});
getContentPane().add(maxSpeed);
maxYawLabel.setText("Rotation Speed");
getContentPane().add(maxYawLabel);
maxYaw.setMaximum(611);
maxYaw.setMinimum(70);
maxYaw.setValue(200);
maxYaw.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
updateYaw(evt);
}
});
getContentPane().add(maxYaw);
controllerDeadzoneLabel.setText("Controller Deadzone");
getContentPane().add(controllerDeadzoneLabel);
controllerDeadzone.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
updateDeadZone(evt);
}
});
getContentPane().add(controllerDeadzone);
cancelButton.setText("Close");
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
getContentPane().add(cancelButton);
okButton.setText("Apply");
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
}
});
getContentPane().add(okButton);
pack();
}// </editor-fold>//GEN-END:initComponents
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
setVisible(false);
}//GEN-LAST:event_cancelButtonActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
updateDrone();
saveSettings();
}//GEN-LAST:event_okButtonActionPerformed
private void updateAlt(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_updateAlt
float value = (float) maxAltitude.getValue() / 1000.0f;
maxAltitude.setToolTipText(value + "m");
maxAltitudeLabel.setText("Max Altitude (" + value + "m)");
}//GEN-LAST:event_updateAlt
private void updateAngle(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_updateAngle
long value = Math.round(Math.toDegrees((float) maxAngle.getValue() / 100.0f));
maxAngle.setToolTipText(value + "");
maxAngleLabel.setText("Max Angle (" + value + "°)");
}//GEN-LAST:event_updateAngle
private void updateSpeed(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_updateSpeed
float value = (float) maxSpeed.getValue() / 1000.0f;
maxSpeed.setToolTipText(value + "m/s");
maxSpeedLabel.setText("Vertical Speed (" + value + "m/s)");
}//GEN-LAST:event_updateSpeed
private void updateDeadZone(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_updateDeadZone
float value = (float) controllerDeadzone.getValue();
controllerDeadzone.setToolTipText(value + "%");
controllerDeadzoneLabel.setText("Controller Deadzone (" + value + "%)");
}//GEN-LAST:event_updateDeadZone
private void updateYaw(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_updateYaw
float value = Math.round(Math.toDegrees((float) maxYaw.getValue() / 100.0f));
maxYaw.setToolTipText(value + "°/s");
maxYawLabel.setText("Rotation Speed (" + value + "°/s)");
}//GEN-LAST:event_updateYaw
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton cancelButton;
private javax.swing.JSlider controllerDeadzone;
private javax.swing.JLabel controllerDeadzoneLabel;
private javax.swing.JSlider maxAltitude;
private javax.swing.JLabel maxAltitudeLabel;
private javax.swing.JSlider maxAngle;
private javax.swing.JLabel maxAngleLabel;
private javax.swing.JSlider maxSpeed;
private javax.swing.JLabel maxSpeedLabel;
private javax.swing.JSlider maxYaw;
private javax.swing.JLabel maxYawLabel;
private javax.swing.JButton okButton;
// End of variables declaration//GEN-END:variables
}
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" value="Controller Mapping"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="314" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="266" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="jTextArea1">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="columns" type="int" value="20"/>
<Property name="rows" type="int" value="5"/>
<Property name="text" type="java.lang.String" value="Enter - takeoff&#xa;Space - landing&#xa;&#xa;W - tilt left&#xa;A - tilt forward&#xa;S - tilt backward&#xa;D - tilt right&#xa;&#xa;Arrow Up - increase altitude&#xa;Arrow Down - decrease altitude&#xa;Arrow Left - yaw Left&#xa;Arrow Right- yaw Right&#xa;&#xa;R - clear emergency signal&#xa;C - change camera view&#xa;E - start/stop video&#xa;F - take a snapshot"/>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="keyMappings"/>
<Property name="AccessibleContext.accessibleParent" type="javax.accessibility.Accessible" editor="org.netbeans.modules.form.ComponentChooserEditor">
<ComponentRef name="Form"/>
</Property>
</AccessibilityProperties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,69 @@
/*
* ControlConfig.java
*
* Created on 25.05.2011, 18:06:24
*/
package com.codeminders.controltower;
/**
*
* @author normenhansen
*/
@SuppressWarnings("serial")
public class KeyboardControlConfig extends javax.swing.JDialog {
private int index = 0;
/** Creates new form ControlConfig */
public KeyboardControlConfig(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("Controller Mapping");
jTextArea1.setEditable(false);
jTextArea1.setColumns(20);
jTextArea1.setRows(5);
jTextArea1.setText("Enter - takeoff\nSpace - landing\n\nW - tilt left\nA - tilt forward\nS - tilt backward\nD - tilt right\n\nArrow Up - increase altitude\nArrow Down - decrease altitude\nArrow Left - yaw Left\nArrow Right- yaw Right\n\nR - clear emergency signal\nC - change camera view\nE - start/stop video\nF - take a snapshot");
jScrollPane1.setViewportView(jTextArea1);
jTextArea1.getAccessibleContext().setAccessibleName("keyMappings");
jTextArea1.getAccessibleContext().setAccessibleParent(this);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 314, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 266, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration//GEN-END:variables
}
@@ -0,0 +1,21 @@
<?xml version="1.1" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,-20,0,0,1,98"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
<Property name="columns" type="int" value="6"/>
<Property name="rows" type="int" value="4"/>
</Layout>
</Form>
@@ -0,0 +1,121 @@
/*
* VideoPanel.java
*
* Created on 21.05.2011, 18:42:10
*/
package com.codeminders.controltower;
import com.codeminders.ardrone.ARDrone;
import com.codeminders.ardrone.DroneVideoListener;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
/**
*
* @author normenhansen
*/
@SuppressWarnings("serial")
public class VideoPanel extends javax.swing.JPanel implements DroneVideoListener
{
private AtomicReference<BufferedImage> image = new AtomicReference<BufferedImage>();
private AtomicBoolean preserveAspect = new AtomicBoolean(true);
private BufferedImage noConnection = new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB);
/** Creates new form VideoPanel */
public VideoPanel()
{
initComponents();
Graphics2D g2d = (Graphics2D) noConnection.getGraphics();
Font f = g2d.getFont().deriveFont(24.0f);
g2d.setFont(f);
g2d.drawString("No video connection", 40, 110);
image.set(noConnection);
}
public void setDrone(ARDrone drone)
{
drone.addImageListener(this);
}
public void setPreserveAspect(boolean preserve)
{
preserveAspect.set(preserve);
}
@Override
public void frameReceived(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
{
BufferedImage im = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
im.setRGB(startX, startY, w, h, rgbArray, offset, scansize);
image.set(im);
repaint();
}
@Override
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int width = getWidth();
int height = getHeight();
drawDroneImage(g2d, width, height);
}
private void drawDroneImage(Graphics2D g2d, int width, int height)
{
BufferedImage im = image.get();
if(im == null)
{
return;
}
int xPos = 0;
int yPos = 0;
if(preserveAspect.get())
{
g2d.setColor(Color.BLACK);
g2d.fill3DRect(0, 0, width, height, false);
float widthUnit = ((float) width / 4.0f);
float heightAspect = (float) height / widthUnit;
float heightUnit = ((float) height / 3.0f);
float widthAspect = (float) width / heightUnit;
if(widthAspect > 4)
{
xPos = (int) (width - (heightUnit * 4)) / 2;
width = (int) (heightUnit * 4);
} else if(heightAspect > 3)
{
yPos = (int) (height - (widthUnit * 3)) / 2;
height = (int) (widthUnit * 3);
}
}
if(im != null)
{
g2d.drawImage(im, xPos, yPos, width, height, null);
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed"
// desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents()
{
setLayout(new java.awt.GridLayout(4, 6));
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
}
@@ -0,0 +1,303 @@
package com.codeminders.controltower.config;
import com.codeminders.ardrone.ARDrone;
import com.codeminders.ardrone.ARDrone.Animation;
import com.codeminders.ardrone.ARDrone.LED;
import com.codeminders.ardrone.ARDrone.VideoChannel;
import com.codeminders.ardrone.util.FileImageRecorder;
import com.codeminders.ardrone.util.FileVideoRecorder;
import com.codeminders.ardrone.util.RecordingSuccessCallback;
import java.io.*;
import java.util.logging.Level;
import org.apache.log4j.Logger;
/**
* This class represents one control mapping for a button and at the same
* time implements all control logic for button presses.
* @author normenhansen
*/
public class AssignableControl {
public enum Command {
TAKEOFF, LAND, TRIM, CLEAR_EMERGENCY, PLAY_ANIMATION, PLAY_LED, RESET,
VIDEO_CYCLE, FRONTAL_CAM, BOTTOM_CAM, BOTTOM_CAM_SMALL, FRONTAL_CAM_SMALL, TAKE_SNAPSHOT, RECORD_VIDEO
}
public enum ControllerButton {
PS, SELECT, START, LEFT_STICK, RIGHT_STICK, TRIANGLE, CIRCLE, CROSS, SQUARE, L1, L2, R1, R2
}
public enum ControllerAxis {
LEFT_X, LEFT_Y, RIGHT_X, RIGHT_Y
}
public enum DroneAxis {
FRONT_BACK, LEFT_RIGHT, UP_DOWN, ROTATE
}
private ControllerButton button;
private Command command;
private Animation anim;
private LED led;
private ControllerAxis controlAxis;
private DroneAxis droneAxis;
private float frequency;
private int duration;
private int delay;
private String prefString;
private static final VideoChannel[] VIDEO_CYCLE = {VideoChannel.HORIZONTAL_ONLY,
VideoChannel.VERTICAL_ONLY, VideoChannel.VERTICAL_IN_HORIZONTAL, VideoChannel.HORIZONTAL_IN_VERTICAL};
private int video_index = 0;
private File recFile;
private FileImageRecorder fir;
private FileVideoRecorder fvr;
/**
* Creates the control from a string that is stored in the java preferences of this app
* @param prefString
*/
public AssignableControl(String prefString) {
String[] strings = prefString.split("/");
if (strings.length < 3) {
throw new IllegalStateException("preference string malformed");
}
button = ControllerButton.valueOf(strings[0]);
command = Command.valueOf(strings[1]);
delay = Integer.parseInt(strings[2]);
switch (command) {
case PLAY_ANIMATION:
anim = Animation.valueOf(strings[3]);
duration = Integer.parseInt(strings[4]);
break;
case PLAY_LED:
led = LED.valueOf(strings[3]);
frequency = Float.parseFloat(strings[4]);
duration = Integer.parseInt(strings[5]);
break;
case RECORD_VIDEO:
case TAKE_SNAPSHOT:
try {
recFile = new File(strings[3].replace('?', File.separatorChar));
} catch (Exception e) {
}
break;
}
this.prefString = prefString;
}
public AssignableControl(ControllerButton button, LED led, int delay, float frequency, int duration) {
this.command = Command.PLAY_LED;
this.delay = delay;
this.led = led;
this.frequency = frequency;
this.duration = duration;
prefString = button.name() + "/" + command.name() + "/" + delay + "/" + led.name() + "/" + frequency + "/" + duration;
}
public AssignableControl(ControllerButton button, Animation anim, int delay, int duration) {
this.command = Command.PLAY_ANIMATION;
this.delay = delay;
this.anim = anim;
this.duration = duration;
prefString = button.name() + "/" + command.name() + "/" + delay + "/" + anim.name() + "/" + duration;
}
public AssignableControl(ControllerButton button, Command command, int delay, File file) {
this.command = command;
this.delay = delay;
this.recFile = file;
prefString = button.name() + "/" + command.name() + "/" + delay + "/" + file.getPath().replace(File.separatorChar, '?');
}
public AssignableControl(ControllerButton button, Command command, int delay) {
this.command = command;
this.delay = delay;
prefString = button.name() + "/" + command.name() + "/" + delay;
}
/**
* Sends the command to the supplied drone
* @param drone
* @throws IOException
*/
public void sendToDrone(final ARDrone drone) throws IOException {
switch (command) {
case PLAY_ANIMATION:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending animation command");
drone.playAnimation(anim, duration);
break;
case PLAY_LED:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending LED command");
drone.playLED(led, frequency, duration);
break;
case CLEAR_EMERGENCY:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending clear emergency");
drone.clearEmergencySignal();
break;
case TRIM:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending trim");
drone.trim();
break;
case TAKEOFF:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending takeoff");
drone.takeOff();
break;
case LAND:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending land");
drone.land();
break;
case RESET:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending reset");
drone.clearEmergencySignal();
drone.trim();
break;
case VIDEO_CYCLE:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending video cycle");
cycleVideoChannel(drone);
break;
case FRONTAL_CAM:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending front cam");
drone.selectVideoChannel(ARDrone.VideoChannel.VERTICAL_ONLY);
break;
case BOTTOM_CAM:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending bottom cam");
drone.selectVideoChannel(ARDrone.VideoChannel.HORIZONTAL_ONLY);
break;
case BOTTOM_CAM_SMALL:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending bottom cam small");
drone.selectVideoChannel(ARDrone.VideoChannel.VERTICAL_IN_HORIZONTAL);
break;
case FRONTAL_CAM_SMALL:
Logger.getLogger(AssignableControl.class.getName()).debug("Sending front cam small");
drone.selectVideoChannel(ARDrone.VideoChannel.HORIZONTAL_IN_VERTICAL);
break;
case TAKE_SNAPSHOT:
Logger.getLogger(AssignableControl.class.getName()).debug("Take snapshot");
takeSnapshot(drone);
break;
case RECORD_VIDEO:
Logger.getLogger(AssignableControl.class.getName()).debug("Record video");
recordVideo(drone);
break;
}
}
private synchronized void takeSnapshot(final ARDrone drone) {
if (fir == null) {
fir = new FileImageRecorder(recFile, 0, "SNAPSHOT-", new RecordingSuccessCallback() {
@Override
public void recordingSuccess(String filename) {
try {
AudioPlayer.playResource(this.getClass(), "/com/codeminders/controltower/sounds/camera.aif");
} catch (Exception ex) {
java.util.logging.Logger.getLogger(AssignableControl.class.getName()).log(Level.SEVERE, "{0}", ex);
}
}
@Override
public void recordingError(String filename, String err, Throwable ex) {
}
});
drone.addImageListener(fir);
}
fir.activate();
}
private synchronized void recordVideo(final ARDrone drone) {
if (fvr == null) {
fvr = new FileVideoRecorder(recFile, 0, "VIDEO-", new RecordingSuccessCallback() {
@Override
public void recordingSuccess(String filename) {
try {
AudioPlayer.playResource(this.getClass(), "/com/codeminders/controltower/sounds/rec_stop.aif");
} catch (Exception ex) {
java.util.logging.Logger.getLogger(AssignableControl.class.getName()).log(Level.SEVERE, "{0}", ex);
}
}
@Override
public void recordingError(String filename, String err, Throwable ex) {
}
}, 20);
drone.addImageListener(fvr);
fvr.startRecording();
try {
AudioPlayer.playResource(this.getClass(), "/com/codeminders/controltower/sounds/rec_start.aif");
} catch (Exception ex) {
java.util.logging.Logger.getLogger(AssignableControl.class.getName()).log(Level.SEVERE, "{0}", ex);
}
} else {
fvr.finishRecording();
fvr = null;
}
}
/**
* Used for VIDEO_CYCLE commands to cycle the video channel
* @param drone
* @throws IOException
*/
private void cycleVideoChannel(ARDrone drone) throws IOException {
if (++video_index == VIDEO_CYCLE.length) {
video_index = 0;
}
drone.selectVideoChannel(VIDEO_CYCLE[video_index]);
}
public ControllerButton getButton() {
return button;
}
public Command getCommand() {
return command;
}
public Animation getAnim() {
return anim;
}
public LED getLed() {
return led;
}
public ControllerAxis getControlAxis() {
return controlAxis;
}
public DroneAxis getDroneAxis() {
return droneAxis;
}
public float getFrequency() {
return frequency;
}
public int getDuration() {
return duration;
}
public int getDelay() {
return delay;
}
public File getRecFile() {
return recFile;
}
/**
* Gets the complete data of this object as a string for storing into java preferences
* @return
*/
public String getPrefString() {
return prefString;
}
}
@@ -0,0 +1,50 @@
package com.codeminders.controltower.config;
import java.io.BufferedInputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
public class AudioPlayer
{
private static final int EXTERNAL_BUFFER_SIZE = 128000;
public static synchronized void playResource(Class resclass, String resname) throws Exception
{
play(AudioSystem.getAudioInputStream(new BufferedInputStream(resclass.getResourceAsStream(resname))));
}
public static synchronized void play(AudioInputStream audioInputStream) throws Exception
{
AudioFormat audioFormat = audioInputStream.getFormat();
SourceDataLine line = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
try
{
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(audioFormat);
line.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
while((nBytesRead = audioInputStream.read(abData, 0, abData.length)) > 0)
{
line.write(abData, 0, nBytesRead);
}
} finally
{
if(line != null)
{
line.drain();
line.close();
}
}
}
}
@@ -0,0 +1,183 @@
package com.codeminders.controltower.config;
import com.codeminders.ardrone.ARDrone;
import com.codeminders.controltower.config.AssignableControl.ControllerButton;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import org.apache.log4j.Logger;
/**
* This class stores the button mapping and manages
* button command sending to the drone
* @author normenhansen
*/
public class ControlMap {
private Preferences prefs;
private HashMap<ControllerButton, List<AssignableControl>> map = new HashMap<ControllerButton, List<AssignableControl>>();
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
public ControlMap() {
prefs = Preferences.userNodeForPackage(this.getClass());
loadMap();
}
/**
* Called from the update loop in ControlTower when a button is pressed
* @param drone
* @param button
* @throws IOException
*/
public synchronized void sendCommand(ARDrone drone, ControllerButton button) throws IOException {
List<AssignableControl> commands = map.get(button);
if (commands == null) {
return;
}
for (Iterator<AssignableControl> it = commands.iterator(); it.hasNext();) {
final AssignableControl assignableCommand = it.next();
if (assignableCommand.getDelay() > 0) {
delayCommand(assignableCommand, drone);
} else {
assignableCommand.sendToDrone(drone);
}
}
}
/**
* Executes a command for a drone with its assigned delay using an Executor
* @param command
* @param drone
*/
private void delayCommand(final AssignableControl command, final ARDrone drone) {
exec.schedule(new Callable<Object>() {
@Override
public Object call() throws Exception {
command.sendToDrone(drone);
return null;
}
}, command.getDelay(), TimeUnit.MILLISECONDS);
}
/**
* Gets the list of control commands that are assigned to a certain button
* @param button
*/
public List<AssignableControl> getControls(ControllerButton button) {
return map.get(button);
}
/**
* Sets the list of control commands for a certain button
* @param button
* @param controls
*/
public synchronized void setControls(ControllerButton button, List<AssignableControl> controls) {
map.put(button, controls);
storeMap();
}
/**
* Loads the mapping from the java preferences
*/
private void loadMap() {
boolean found = false;
try {
String[] keys = prefs.keys();
for (int i = 0; i < keys.length; i++) {
String string = keys[i];
if (string.startsWith("CONTROL_MAPPING")) {
String mapping = prefs.get(string, "");
AssignableControl command = new AssignableControl(mapping);
List<AssignableControl> commands = map.get(command.getButton());
if (commands == null) {
commands = new LinkedList<AssignableControl>();
map.put(command.getButton(), commands);
}
commands.add(0, command);
Logger.getLogger(ControlMap.class.getName()).debug("Load command:{0} "+command.getPrefString());
found = true;
}
}
} catch (BackingStoreException ex) {
Logger.getLogger(ControlMap.class.getName()).error("{0}", ex);
}
if (!found) {
Logger.getLogger(ControlMap.class.getName()).debug("Load default button map");
createDefaultMapping();
}
}
/**
* Creates the default mapping in case no settings are stored yet
*/
private void createDefaultMapping() {
map.put(ControllerButton.PS, new LinkedList<AssignableControl>());
map.get(ControllerButton.PS).add(new AssignableControl(ControllerButton.PS, AssignableControl.Command.RESET, 0));
map.put(ControllerButton.START, new LinkedList<AssignableControl>());
map.get(ControllerButton.START).add(new AssignableControl(ControllerButton.START, AssignableControl.Command.TAKEOFF, 0));
map.put(ControllerButton.SELECT, new LinkedList<AssignableControl>());
map.get(ControllerButton.SELECT).add(new AssignableControl(ControllerButton.SELECT, AssignableControl.Command.LAND, 0));
map.put(ControllerButton.TRIANGLE, new LinkedList<AssignableControl>());
map.get(ControllerButton.TRIANGLE).add(new AssignableControl(ControllerButton.TRIANGLE, AssignableControl.Command.VIDEO_CYCLE, 0));
map.put(ControllerButton.SQUARE, new LinkedList<AssignableControl>());
map.get(ControllerButton.SQUARE).add(new AssignableControl(ControllerButton.SQUARE, AssignableControl.Command.TAKE_SNAPSHOT, 0));
map.put(ControllerButton.CIRCLE, new LinkedList<AssignableControl>());
map.get(ControllerButton.CIRCLE).add(new AssignableControl(ControllerButton.CIRCLE, AssignableControl.Command.RECORD_VIDEO, 0));
}
/**
* Stores the mapping in the java preferences
*/
private void storeMap() {
clearMap();
int i = 0;
Collection<List<AssignableControl>> list = map.values();
for (Iterator<List<AssignableControl>> it = list.iterator(); it.hasNext();) {
List<AssignableControl> list1 = it.next();
for (Iterator<AssignableControl> it1 = list1.iterator(); it1.hasNext();) {
AssignableControl assignableCommand = it1.next();
prefs.put("CONTROL_MAPPING_" + i++, assignableCommand.getPrefString());
}
}
try {
prefs.flush();
} catch (BackingStoreException ex) {
Logger.getLogger(ControlMap.class.getName()).error("{0}", ex);
}
}
/**
* Clears the used preferences from all mappings
*/
private void clearMap() {
String[] keys;
try {
keys = prefs.keys();
for (int i = 0; i < keys.length; i++) {
String string = keys[i];
if (string.startsWith("CONTROL_MAPPING")) {
prefs.remove(string);
}
}
} catch (BackingStoreException ex) {
Logger.getLogger(ControlMap.class.getName()).error("{0}", ex);
}
}
}
Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 3.2 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 3.2 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 562 B

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 562 B

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 40 KiB

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 622 B

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 267 B

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 266 B

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 405 B

@@ -0,0 +1,9 @@
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%r [%t] %-5p %c{2} %x - %m%n
+83
Ver Arquivo
@@ -0,0 +1,83 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.codeminders</groupId>
<artifactId>javadrone</artifactId>
<version>${currentVersion}</version>
</parent>
<artifactId>javadrone-api</artifactId>
<name>javadrone-api</name>
<description>Java API (without using native code) to control AR.Drone</description>
<build>
<finalName>javadrone-api-${currentVersion}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<inherited>true</inherited>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadSources>true</downloadSources>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>local</id>
<name>Local repository</name>
<url>file:${basedir}/../lib/maven</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.codeminders</groupId>
<artifactId>hidapi</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,639 @@
package com.codeminders.ardrone;
import java.io.IOException;
import java.net.*;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import com.codeminders.ardrone.NavData.FlyingState;
import com.codeminders.ardrone.commands.*;
public class ARDrone
{
public enum State
{
DISCONNECTED, CONNECTING, BOOTSTRAP, DEMO, ERROR, TAKING_OFF, LANDING
}
public enum VideoChannel
{
HORIZONTAL_ONLY, VERTICAL_ONLY, VERTICAL_IN_HORIZONTAL, HORIZONTAL_IN_VERTICAL
}
public enum Animation
{
PHI_M30_DEG(0), PHI_30_DEG(1), THETA_M30_DEG(2), THETA_30_DEG(3), THETA_20DEG_YAW_200DEG(4), THETA_20DEG_YAW_M200DEG(
5), TURNAROUND(6), TURNAROUND_GODOWN(7), YAW_SHAKE(8), YAW_DANCE(9), PHI_DANCE(10), THETA_DANCE(11), VZ_DANCE(
12), WAVE(13), PHI_THETA_MIXED(14), DOUBLE_PHI_THETA_MIXED(15), ANIM_MAYDAY(16);
private int value;
private Animation(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
}
public enum LED
{
BLINK_GREEN_RED(0), BLINK_GREEN(1), BLINK_RED(2), BLINK_ORANGE(3), SNAKE_GREEN_RED(4), FIRE(5), STANDARD(6), RED(
7), GREEN(8), RED_SNAKE(9), BLANK(10), RIGHT_MISSILE(11), LEFT_MISSILE(12), DOUBLE_MISSILE(13), FRONT_LEFT_GREEN_OTHERS_RED(
14), FRONT_RIGHT_GREEN_OTHERS_RED(15), REAR_RIGHT_GREEN_OTHERS_RED(16), REAR_LEFT_GREEN_OTHERS_RED(17), LEFT_GREEN_RIGHT_RED(
18), LEFT_RED_RIGHT_GREEN(19), BLINK_STANDARD(20);
private int value;
private LED(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
}
public enum ConfigOption
{
ACCS_OFFSET("control:accs_offset"), ACCS_GAINS("control:accs_gains"), GYROS_OFFSET("control:gyros_offset"), GYROS_GAINS(
"control:gyros_gains"), GYROS110_OFFSET("control:gyros110_offset"), GYROS110_GAINS(
"control:gyros110_gains"), GYRO_OFFSET_THR_X("control:gyro_offset_thr_x"), GYRO_OFFSET_THR_Y(
"control:gyro_offset_thr_y"), GYRO_OFFSET_THR_Z("control:gyro_offset_thr_z"), PWM_REF_GYROS(
"control:pwm_ref_gyros"), CONTROL_LEVEL("control:control_level"), SHIELD_ENABLE("control:shield_enable"), EULER_ANGLE_MAX(
"control:euler_angle_max"), ALTITUDE_MAX("control:altitude_max"), ALTITUDE_MIN("control:altitude_min"), CONTROL_TRIM_Z(
"control:control_trim_z"), CONTROL_IPHONE_TILT("control:control_iphone_tilt"), CONTROL_VZ_MAX(
"control:control_vz_max"), CONTROL_YAW("control:control_yaw"), OUTDOOR("control:outdoor"), FLIGHT_WITHOUT_SHELL(
"control:flight_without_shell"), BRUSHLESS("control:brushless"), AUTONOMOUS_FLIGHT(
"control:autonomous_flight"), MANUAL_TRIM("control:manual_trim"), INDOOR_EULER_ANGLE_MAX(
"control:indoor_euler_angle_max"), INDOOR_CONTROL_VZ_MAX("control:indoor_control_vz_max"), INDOOR_CONTROL_YAW(
"control:indoor_control_yaw"), OUTDOOR_EULER_ANGLE_MAX("control:outdoor_euler_angle_max"), OUTDOOR_CONTROL_VZ_MAX(
"control:outdoor_control_vz_max"), OUTDOOR_CONTROL_YAW("outdoor_control:control_yaw");
private String value;
private ConfigOption(String value)
{
this.value = value;
}
public String getValue()
{
return value;
}
}
private Logger log = Logger.getLogger(getClass().getName());
private static final int CMD_QUEUE_SIZE = 64;
private State state = State.DISCONNECTED;
private Object state_mutex = new Object();
private static final int NAVDATA_PORT = 5554;
private static final int VIDEO_PORT = 5555;
// private static final int CONTROL_PORT = 5559;
private static byte[] DEFAULT_DRONE_IP = { (byte) 192, (byte) 168, (byte) 1, (byte) 1 };
private InetAddress drone_addr;
private DatagramSocket cmd_socket;
// private Socket control_socket;
private CommandQueue cmd_queue = new CommandQueue(CMD_QUEUE_SIZE);
private NavDataReader nav_data_reader;
private VideoReader video_reader;
private CommandSender cmd_sender;
private Thread nav_data_reader_thread;
private Thread cmd_sending_thread;
private Thread video_reader_thread;
private boolean combinedYawMode = true;
private boolean emergencyMode = true;
private Object emergency_mutex = new Object();
private List<DroneStatusChangeListener> status_listeners = new LinkedList<DroneStatusChangeListener>();
private List<DroneVideoListener> image_listeners = new LinkedList<DroneVideoListener>();
private List<NavDataListener> navdata_listeners = new LinkedList<NavDataListener>();
public ARDrone() throws UnknownHostException
{
this(InetAddress.getByAddress(DEFAULT_DRONE_IP));
}
public ARDrone(InetAddress drone_addr)
{
this.drone_addr = drone_addr;
}
public void addImageListener(DroneVideoListener l)
{
synchronized(image_listeners)
{
image_listeners.add(l);
}
}
public void removeImageListener(DroneVideoListener l)
{
synchronized(image_listeners)
{
image_listeners.remove(l);
}
}
public void clearImageListeners()
{
synchronized(image_listeners)
{
image_listeners.clear();
}
}
public void addStatusChangeListener(DroneStatusChangeListener l)
{
synchronized(status_listeners)
{
status_listeners.add(l);
}
}
public void removeStatusChangeListener(DroneStatusChangeListener l)
{
synchronized(status_listeners)
{
status_listeners.remove(l);
}
}
public void clearStatusChangeListeners()
{
synchronized(status_listeners)
{
status_listeners.clear();
}
}
public void addNavDataListener(NavDataListener l)
{
synchronized(navdata_listeners)
{
navdata_listeners.add(l);
}
}
public void removeNavDataListener(NavDataListener l)
{
synchronized(navdata_listeners)
{
navdata_listeners.remove(l);
}
}
public void clearNavDataListeners()
{
synchronized(navdata_listeners)
{
navdata_listeners.clear();
}
}
private void changeState(State newstate) throws IOException
{
if(newstate == State.ERROR)
changeToErrorState(null);
synchronized(state_mutex)
{
if(state != newstate)
{
log.debug("State changed from " + state + " to " + newstate);
state = newstate;
// We automatically switch to DEMO from bootstrap
if(state == State.BOOTSTRAP)
sendDemoNavigationData();
state_mutex.notifyAll();
}
}
if(newstate == State.DEMO)
{
synchronized(status_listeners)
{
for(DroneStatusChangeListener l : status_listeners)
l.ready();
}
}
}
public void changeToErrorState(Exception ex)
{
synchronized(state_mutex)
{
try
{
if(state != State.DISCONNECTED)
doDisconnect();
} catch(IOException e)
{
// Ignoring exceptions on disconnection
}
log.debug("State changed from " + state + " to " + State.ERROR + " with exception ", ex);
state = State.ERROR;
state_mutex.notifyAll();
}
}
public void clearEmergencySignal() throws IOException
{
synchronized(emergency_mutex)
{
if(isEmergencyMode())
cmd_queue.add(new EmergencyCommand());
}
}
/**
* Initiate drone connection procedure.
*
* @throws IOException
*/
public void connect() throws IOException
{
try
{
cmd_socket = new DatagramSocket();
// control_socket = new Socket(drone_addr, CONTROL_PORT);
cmd_sender = new CommandSender(cmd_queue, this, drone_addr, cmd_socket);
cmd_sending_thread = new Thread(cmd_sender);
cmd_sending_thread.start();
nav_data_reader = new NavDataReader(this, drone_addr, NAVDATA_PORT);
nav_data_reader_thread = new Thread(nav_data_reader);
nav_data_reader_thread.start();
video_reader = new VideoReader(this, drone_addr, VIDEO_PORT);
video_reader_thread = new Thread(video_reader);
video_reader_thread.start();
changeState(State.CONNECTING);
} catch(IOException ex)
{
changeToErrorState(ex);
throw ex;
}
}
public void disableAutomaticVideoBitrate() throws IOException
{
cmd_queue.add(new ConfigureCommand("video:bitrate_control_mode", "0"));
}
public void disconnect() throws IOException
{
try
{
doDisconnect();
} finally
{
changeState(State.DISCONNECTED);
}
}
private void doDisconnect() throws IOException
{
if(cmd_queue != null)
cmd_queue.add(new QuitCommand());
if(nav_data_reader != null)
nav_data_reader.stop();
if(video_reader != null)
video_reader.stop();
if(cmd_socket != null)
cmd_socket.close();
// Only the following method can throw an exception.
// We call it last, to ensure it won't prevent other
// cleanup operations from being completed
// control_socket.close();
}
/**
* Enables the automatic bitrate control of the video stream. Enabling this
* configuration will reduce the bandwith used by the video stream under bad
* Wi-Fi conditions, reducing the commands latency. Note : Before enabling
* this config, make sure that your video decoder is able to handle the
* variable bitrate mode !
*
* @throws IOException
*/
public void enableAutomaticVideoBitrate() throws IOException
{
setConfigOption("video:bitrate_control_mode", "1");
}
public void hover() throws IOException
{
cmd_queue.add(new HoverCommand());
}
public boolean isCombinedYawMode()
{
return combinedYawMode;
}
public boolean isEmergencyMode()
{
return emergencyMode;
}
public void land() throws IOException
{
// TODO: Review of possible race condition
cmd_queue.add(new LandCommand());
changeState(State.LANDING);
}
/**
* Move the drone
*
* @param left_right_tilt The left-right tilt (aka. "drone roll" or phi
* angle) argument is a percentage of the maximum inclination as
* configured here. A negative value makes the drone tilt to its
* left, thus flying leftward. A positive value makes the drone
* tilt to its right, thus flying rightward.
* @param front_back_tilt The front-back tilt (aka. "drone pitch" or theta
* angle) argument is a percentage of the maximum inclination as
* configured here. A negative value makes the drone lower its
* nose, thus flying frontward. A positive value makes the drone
* raise its nose, thus flying backward. The drone translation
* speed in the horizontal plane depends on the environment and
* cannot be determined. With roll or pitch values set to 0, the
* drone will stay horizontal but continue sliding in the air
* because of its inertia. Only the air resistance will then make
* it stop.
* @param vertical_speed The vertical speed (aka. "gaz") argument is a
* percentage of the maximum vertical speed as defined here. A
* positive value makes the drone rise in the air. A negative
* value makes it go down.
* @param angular_speed The angular speed argument is a percentage of the
* maximum angular speed as defined here. A positive value makes
* the drone spin right; a negative value makes it spin left.
* @throws IOException
*/
public void move(float left_right_tilt, float front_back_tilt, float vertical_speed, float angular_speed)
throws IOException
{
cmd_queue
.add(new MoveCommand(combinedYawMode, left_right_tilt, front_back_tilt, vertical_speed, angular_speed));
}
// Callback used by receiver
public void navDataReceived(NavData nd)
{
if(nd.isBatteryTooLow() || nd.isNotEnoughPower())
{
log.error("Battery pb " + nd.toString());
}
synchronized(emergency_mutex)
{
emergencyMode = nd.isEmergency();
}
try
{
synchronized(state_mutex)
{
if(state != State.CONNECTING && nd.isControlReceived())
{
log.debug("Control received! ACK!");
cmd_queue.add(new ControlCommand(5, 0));
}
if(state == State.TAKING_OFF && nd.getFlyingState() == FlyingState.FLYING)
{
log.debug("Take off success");
cmd_queue.clear(); // Maybe we should just remove
// LAND/TAKEOFF comand
// instead of nuking the whole queue?
changeState(State.DEMO);
} else if(state == State.LANDING && nd.getFlyingState() == FlyingState.LANDED)
{
log.debug("Landing success");
cmd_queue.clear(); // Maybe we should just remove
// LAND/TAKEOFF comand
// instead of nuking the whole queue?
changeState(State.DEMO);
} else if(state != State.BOOTSTRAP && nd.getMode() == NavData.Mode.BOOTSTRAP)
{
changeState(State.BOOTSTRAP);
} else if(state == State.BOOTSTRAP && nd.getMode() == NavData.Mode.DEMO)
{
changeState(State.DEMO);
}
if(state != State.CONNECTING && nd.isCommunicationProblemOccurred())
{
// 50ms communications watchdog has been triggered
cmd_queue.add(new KeepAliveCommand());
}
}
} catch(IOException e)
{
log.error("Error changing the state", e);
}
if(state == State.DEMO)
{
synchronized(navdata_listeners)
{
for(NavDataListener l : navdata_listeners)
l.navDataReceived(nd);
}
}
}
public void playAnimation(int animation_no, int duration) throws IOException
{
cmd_queue.add(new PlayAnimationCommand(animation_no, duration));
}
public void playAnimation(Animation animation, int duration) throws IOException
{
cmd_queue.add(new PlayAnimationCommand(animation.getValue(), duration));
}
public void playLED(int animation_no, float freq, int duration) throws IOException
{
cmd_queue.add(new PlayLEDCommand(animation_no, freq, duration));
}
public void playLED(LED animation, float freq, int duration) throws IOException
{
cmd_queue.add(new PlayLEDCommand(animation.getValue(), freq, duration));
}
public void selectVideoChannel(VideoChannel c) throws IOException
{
/*
* Current implementation supports 4 different channels : -
* ARDRONE_VIDEO_CHANNEL_HORI - ARDRONE_VIDEO_CHANNEL_VERT -
* ARDRONE_VIDEO_CHANNEL_LARGE_HORI_SMALL_VERT -
* ARDRONE_VIDEO_CHANNEL_LARGE_VERT_SMALL_HORI
*
* AT command example : AT*CONFIG=605,"video:video_channel","2"
*/
String s;
switch(c)
{
case HORIZONTAL_ONLY: // ARDRONE_VIDEO_CHANNEL_HORI
s = "0";
break;
case VERTICAL_ONLY: // ARDRONE_VIDEO_CHANNEL_VERT
s = "1";
break;
case VERTICAL_IN_HORIZONTAL: // ARDRONE_VIDEO_CHANNEL_LARGE_HORI_SMALL_VERT
s = "2";
break;
case HORIZONTAL_IN_VERTICAL: // ARDRONE_VIDEO_CHANNEL_LARGE_VERT_SMALL_HORI
s = "3";
break;
default:
assert (false);
return;
}
cmd_queue.add(new ConfigureCommand("video:video_channel", s));
}
public void sendAllNavigationData() throws IOException
{
setConfigOption("general:navdata_demo", "FALSE");
}
public void sendDemoNavigationData() throws IOException
{
setConfigOption("general:navdata_demo", "TRUE");
}
public void sendEmergencySignal() throws IOException
{
synchronized(emergency_mutex)
{
if(!isEmergencyMode())
cmd_queue.add(new EmergencyCommand());
}
}
public void setCombinedYawMode(boolean combinedYawMode)
{
this.combinedYawMode = combinedYawMode;
}
public void setConfigOption(String name, String value) throws IOException
{
cmd_queue.add(new ConfigureCommand(name, value));
}
public void setConfigOption(ConfigOption option, String value) throws IOException
{
cmd_queue.add(new ConfigureCommand(option.getValue(), value));
}
public void takeOff() throws IOException
{
// TODO: review for possible race condition
if (!isEmergencyMode()) {
cmd_queue.add(new TakeOffCommand());
changeState(State.TAKING_OFF);
}
}
public void trim() throws IOException
{
cmd_queue.add(new FlatTrimCommand());
}
// Callback used by VideoReciver
public void videoFrameReceived(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
{
synchronized(image_listeners)
{
for(DroneVideoListener l : image_listeners)
l.frameReceived(startX, startY, w, h, rgbArray, offset, scansize);
}
}
/**
* Wait for drone to switch to demo mode. Throw exception if this not
* succeeded within given timeout. Should be called right after connect().
*
* This is a convenience function. Another way to achieve the same result is
* using status change callback.
*
* @param how_long
* @throws IOException
*/
public void waitForReady(long how_long) throws IOException
{
long since = System.currentTimeMillis();
synchronized(state_mutex)
{
while(true)
{
if((System.currentTimeMillis() - since) >= how_long)
{
try
{
disconnect();
} catch(IOException e)
{
}
// Timeout, too late
throw new IOException("Timeout connecting to ARDrone");
} else if(state == State.DEMO)
{
return; // OK! We are now connected
} else if(state == State.ERROR || state == State.DISCONNECTED)
{
throw new IOException("Connection Error");
}
long p = Math.min(how_long - (System.currentTimeMillis() - since), how_long);
if(p > 0)
{
try
{
state_mutex.wait(p);
} catch(InterruptedException e)
{
// Ignore
}
}
}
}
}
}
@@ -0,0 +1,104 @@
package com.codeminders.ardrone;
import java.util.Iterator;
import java.util.LinkedList;
import org.apache.log4j.Logger;
public class CommandQueue
{
private LinkedList<DroneCommand> data;
private int maxSize;
@SuppressWarnings("unused")
private Logger log = Logger.getLogger(getClass().getName());
public CommandQueue(int maxSize)
{
data = new LinkedList<DroneCommand>();
this.maxSize = maxSize;
}
public synchronized DroneCommand take() throws InterruptedException
{
while(true)
{
DroneCommand res = data.pollLast();
if(res != null)
{
// log.debug("[" + data.size() + "] Returning " + res);
if(res.isSticky())
{
int sc = res.incrementStickyCounter();
data.addLast(res);
if(sc > 1)
Thread.sleep(res.getStickyRate());
}
return res;
} else
{
// log.debug("Waiting for data");
wait();
}
}
}
public synchronized void add(DroneCommand cmd)
{
Iterator<DroneCommand> i = data.iterator();
int p = cmd.getPriority();
int pos = -1;
while(i.hasNext())
{
DroneCommand x = i.next();
pos++;
int xp = x.getPriority();
if(xp < p)
{
// Skipping
continue;
} else
{
// Found insertion point.
if(!x.replaces(cmd))
{
// log.debug("[" + data.size() + "] Adding command " +
// cmd);
data.add(pos, cmd);
notify();
} else
{
// log.debug("Replacing duplicate element " + cmd);
data.set(pos, cmd);
}
cmd = null; // inserted
break;
}
}
if(cmd != null)
{
// log.debug("[" + data.size() + "] Adding command " + cmd);
data.addLast(cmd);
notify();
}
if(data.size() > maxSize)
{
// TODO: trim
}
}
public synchronized int size()
{
return data.size();
}
public synchronized void clear()
{
data.clear();
notify();
}
}
@@ -0,0 +1,66 @@
package com.codeminders.ardrone;
import java.io.IOException;
import java.net.*;
import org.apache.log4j.Logger;
import com.codeminders.ardrone.commands.*;
public class CommandSender implements Runnable
{
private static final int CMD_PORT = 5556;
private CommandQueue cmd_queue;
private ARDrone drone;
private InetAddress drone_addr;
private DatagramSocket cmd_socket;
private int sequence = 1;
private Logger log = Logger.getLogger(getClass().getName());
public CommandSender(CommandQueue cmd_queue, ARDrone drone, InetAddress drone_addr, DatagramSocket cmd_socket)
{
this.cmd_queue = cmd_queue;
this.drone = drone;
this.drone_addr = drone_addr;
this.cmd_socket = cmd_socket;
}
@Override
public void run()
{
while(true)
{
try
{
DroneCommand c = cmd_queue.take();
if(c instanceof QuitCommand)
{
// Terminating
break;
}
if(c instanceof ATCommand)
{
ATCommand cmd = (ATCommand) c;
//if(!(c instanceof KeepAliveCommand) && !(c instanceof MoveCommand) && !(c instanceof HoverCommand) && c.getStickyCounter()==0)
log.debug("Q[" + cmd_queue.size() + "]Sending AT command " + c);
byte[] pdata = cmd.getPacket(sequence++); // TODO: pass
// sequence number
DatagramPacket p = new DatagramPacket(pdata, pdata.length, drone_addr, CMD_PORT);
cmd_socket.send(p);
}
} catch(InterruptedException e)
{
// ignoring
} catch(IOException e)
{
drone.changeToErrorState(e);
break;
}
}
}
}
@@ -0,0 +1,125 @@
package com.codeminders.ardrone;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Set;
public abstract class DataReader implements Runnable {
private static final int RECONNECT_TIMEOUT = 1000;
private static final int MAX_TMEOUT = 5;
protected DatagramChannel channel;
ARDrone drone;
protected Selector selector;
private boolean done;
private InetAddress drone_addr;
private int data_port;
private long timeOfLastMessage = 0;
private int buffer_size;
public DataReader(ARDrone drone, InetAddress drone_addr, int data_port, int buffer_size) throws ClosedChannelException, IOException {
super();
this.drone = drone;
this.drone_addr = drone_addr;
this.data_port = data_port;
this.buffer_size = buffer_size;
connect();
}
private void connect() throws IOException, ClosedChannelException {
channel = DatagramChannel.open();
channel.configureBlocking(false);
channel.socket().bind(new InetSocketAddress(data_port));
channel.connect(new InetSocketAddress(drone_addr, data_port));
selector = Selector.open();
channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
private void disconnect() {
try {
if (selector.isOpen())
selector.close();
} catch (IOException iox)
{
// Ignore
}
if (!channel.socket().isClosed()) {
channel.socket().close();
}
try {
if (channel.isConnected())
channel.disconnect();
} catch (IOException iox)
{
// Ignore
}
}
@Override
public void run()
{
try
{
ByteBuffer inbuf = ByteBuffer.allocate(buffer_size);
done = false;
while(!done)
{
selector.select(MAX_TMEOUT);
if(done)
{
disconnect();
break;
}
Set readyKeys = selector.selectedKeys();
Iterator iterator = readyKeys.iterator();
if (!iterator.hasNext()) {
if (timeOfLastMessage > 0 && System.currentTimeMillis() - timeOfLastMessage > RECONNECT_TIMEOUT ) {
disconnect();
try {
connect();
} catch (Exception e) {
// ignore
}
timeOfLastMessage = System.currentTimeMillis();
}
}
while(iterator.hasNext())
{
timeOfLastMessage = System.currentTimeMillis();
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
handleReceivedMessageKey(key, inbuf);
}
}
} catch(Exception e)
{
drone.changeToErrorState(e);
}
}
abstract void handleReceivedMessageKey(SelectionKey key, ByteBuffer inbuf) throws Exception;
public void stop()
{
done = true;
selector.wakeup();
}
}
@@ -0,0 +1,36 @@
package com.codeminders.ardrone;
public class Dimension
{
private int width;
private int height;
public Dimension(int width, int height)
{
super();
this.width = width;
this.height = height;
}
public int getWidth()
{
return width;
}
public void setWidth(int width)
{
this.width = width;
}
public int getHeight()
{
return height;
}
public void setHeight(int height)
{
this.height = height;
}
}
@@ -0,0 +1,70 @@
package com.codeminders.ardrone;
public abstract class DroneCommand
{
protected static final int MIN_PRIORITY = 0;
protected static final int HIGH_PRIORITY = 50;
protected static final int VERY_HIGH_PRIORITY = 90;
protected static final int MAX_PRIORITY = 100;
protected static final long DEFAULT_STICKY_RATE_MS = 100;
protected static final String LAND_TAKEOFF_CATEGORY = "takeoffland";
private int sticky_counter = 0;
public abstract int getPriority();
public String getCategory()
{
return null;
}
public boolean isSticky()
{
return false;
}
/**
* For sticky packets indicates how many times it has been sent.
*
* @return current value
*/
public int incrementStickyCounter()
{
return ++sticky_counter;
}
public int getStickyCounter()
{
return sticky_counter;
}
/**
* For sticky packets indicates delay between sending repeated packets;
*/
public long getStickyRate()
{
return DEFAULT_STICKY_RATE_MS;
}
/**
* This method is used to check if 2 commands are are relaceable by each
* other.
*
* @param cmd
* @return true if they are replaceable
*/
public boolean replaces(DroneCommand cmd)
{
if(equals(cmd))
{
return true;
} else
{
String c = getCategory();
return c != null && c.equals(cmd.getCategory());
}
}
}
@@ -0,0 +1,13 @@
package com.codeminders.ardrone;
public interface DroneStatusChangeListener
{
/**
* This method is called whenever the drone changes from BOOTSTRAP or
* ERROR modes to DEMO mode. Could be used for user-supplied initialization
*/
void ready();
}
@@ -0,0 +1,7 @@
package com.codeminders.ardrone;
public interface DroneVideoListener
{
void frameReceived(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize);
}
@@ -0,0 +1,650 @@
package com.codeminders.ardrone;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import com.codeminders.ardrone.VisionTag.VisionTagType;
public class NavData
{
public static enum ControlAlgorithm
{
EULER_ANGELS_CONTROL, ANGULAR_SPEED_CONTROL
}
public static enum CtrlState
{
DEFAULT, INIT, LANDED, FLYING, HOVERING, TEST, TRANS_TAKEOFF, TRANS_GOTOFIX, TRANS_LANDING;
public static CtrlState fromInt(int v) throws NavDataFormatException
{
switch(v)
{
case 0:
return DEFAULT;
case 1:
return INIT;
case 2:
return LANDED;
case 3:
return FLYING;
case 4:
return HOVERING;
case 5:
return TEST;
case 6:
return TRANS_TAKEOFF;
case 7:
return TRANS_GOTOFIX;
case 8:
return TRANS_LANDING;
default:
throw new NavDataFormatException("Invalid control state " + v);
}
}
}
public static enum FlyingState
{
FLYING, TAKING_OFF, LANDING, LANDED;
public static FlyingState fromControlState(CtrlState state)
{
switch(state)
{
case FLYING:
case HOVERING:
case TRANS_GOTOFIX:
return FlyingState.FLYING;
case TRANS_TAKEOFF:
return FlyingState.TAKING_OFF;
case TRANS_LANDING:
return FlyingState.LANDING;
default:
return FlyingState.LANDED;
}
}
}
public static enum Mode
{
BOOTSTRAP, DEMO
}
public static enum NavDataTag
{
NAVDATA_DEMO_TAG(0), NAVDATA_TIME_TAG(1), NAVDATA_RAW_MEASURES_TAG(2), NAVDATA_PHYS_MEASURES_TAG(3), NAVDATA_GYROS_OFFSETS_TAG(
4), NAVDATA_EULER_ANGLES_TAG(5), NAVDATA_REFERENCES_TAG(6), NAVDATA_TRIMS_TAG(7), NAVDATA_RC_REFERENCES_TAG(
8), NAVDATA_PWM_TAG(9), NAVDATA_ALTITUDE_TAG(10), NAVDATA_VISION_RAW_TAG(11), NAVDATA_VISION_OF_TAG(12), NAVDATA_VISION_TAG(
13), NAVDATA_VISION_PERF_TAG(14), NAVDATA_TRACKERS_SEND_TAG(15), NAVDATA_VISION_DETECT_TAG(16), NAVDATA_WATCHDOG_TAG(
17), NAVDATA_ADC_DATA_FRAME_TAG(18), NAVDATA_VIDEO_STREAM_TAG(19), NAVDATA_CKS_TAG(0xFFFF);
private int value;
private NavDataTag(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
}
private static final Logger log = Logger.getLogger(NavData.class.getName());
public static float byteArrayToFloat(byte[] b, int offset)
{
return Float.intBitsToFloat(byteArrayToInt(b, offset));
}
/**
* Convert the byte array to an int.
*
* @param b The byte array
* @return The integer
*/
public static int byteArrayToInt(byte[] b)
{
return byteArrayToInt(b, 0);
}
/**
* Convert the byte array to an int starting from the given offset.
*
* @param b The byte array
* @param offset The array offset
* @return The integer
*/
public static int byteArrayToInt(byte[] b, int offset)
{
int value = 0;
for(int i = 3; i >= 0; i--)
{
int shift = i * 8;
value += (b[i + offset] & 0x000000FF) << shift;
}
return value;
}
/**
* Convert the byte array to an int starting from the given offset.
*
* @param b The byte array
* @param offset The array offset
* @return The short
*/
public static int byteArrayToShort(byte[] b, int offset)
{
return ((b[offset + 1] & 0x000000FF) << 8) + (b[offset] & 0x000000FF);
}
public static NavData createFromData(byte[] buf) throws NavDataFormatException
{
log.debug("Parsing navdata len=" + buf.length);
NavData data = new NavData();
data.mode = NavData.Mode.BOOTSTRAP; // Assume we are in bootstrap
int offset = 0;
int header = byteArrayToInt(buf, offset);
if(header != 0x55667788)
throw new NavDataFormatException("Error parsing NavData");
offset += 4;
int state = byteArrayToInt(buf, offset);
offset += 4;
parseState(data, state);
data.sequence = byteArrayToInt(buf, offset);
offset += 4;
// int vision_flag = byteArrayToInt(buf, offset);
offset += 4;
// Read options
while(offset < buf.length)
{
int option_tag = byteArrayToShort(buf, offset);
offset += 2;
int option_len = byteArrayToShort(buf, offset);
offset += 2;
if(option_len == 0)
throw new NavDataFormatException("Zero-len option with tag " + option_tag);
// log.debug("At offset " + (offset - 4) + " found option " +
// option_tag + " with len=" + option_len);
if(option_tag == NavDataTag.NAVDATA_DEMO_TAG.getValue())
{
parseDemoNavData(data, buf, offset);
data.mode = NavData.Mode.DEMO;
} else if(option_tag == NavDataTag.NAVDATA_CKS_TAG.getValue())
{
// this is last tag. We do not unpack it yet, but we gracefully
// exit if it has been encountered.
break;
} else if(option_tag == NavDataTag.NAVDATA_VISION_DETECT_TAG.getValue())
{
List<VisionTag> vtags = parseVisionTags(data, buf, offset);
if(vtags != null)
data.setVisionTags(vtags);
} else
{
log.warn("Skipping unknown NavData option with tag=" + option_tag);
}
offset = offset + option_len - 4;
}
// TODO: calculate checksum
log.debug("Got Nav data. mode " + data.mode);
return data;
}
private static List<VisionTag> parseVisionTags(NavData data, byte[] buf, int offset) throws NavDataFormatException
{
int nb_detected = byteArrayToInt(buf, offset);
offset += 4;
if(nb_detected!=0)
log.debug("" + nb_detected + " vision tags detected");
if(nb_detected == 0)
return null;
assert (nb_detected > 0);
List<VisionTag> res = new ArrayList<VisionTag>(nb_detected);
for(int i = 0; i < nb_detected; i++)
{
int type = byteArrayToInt(buf, offset + 4 * i);
int xc = byteArrayToInt(buf, offset + 4 * i + 1 * nb_detected * 4);
int yc = byteArrayToInt(buf, offset + 4 * i + 2 * nb_detected * 4);
int width = byteArrayToInt(buf, offset + 4 * i + 3 * nb_detected * 4);
int height = byteArrayToInt(buf, offset + 4 * i + 4 * nb_detected * 4);
int dist = byteArrayToInt(buf, offset + 4 * i + 5 * nb_detected * 4);
VisionTag vt = new VisionTag(VisionTagType.fromInt(type), new Point(xc, yc), new Dimension(width, height),
dist);
log.debug("Vision#" + i + " " + vt.toString());
res.add(vt);
}
return res;
}
private static void parseDemoNavData(NavData data, byte[] buf, int offset) throws NavDataFormatException
{
data.ctrl_state = CtrlState.fromInt(byteArrayToInt(buf, offset) >> 16);
log.debug("Ctrl State " + data.ctrl_state);
offset += 4;
data.battery = byteArrayToInt(buf, offset);
offset += 4;
data.pitch = byteArrayToFloat(buf, offset) / 1000;
offset += 4;
data.roll = byteArrayToFloat(buf, offset) / 1000;
offset += 4;
data.yaw = byteArrayToFloat(buf, offset) / 1000;
offset += 4;
data.altitude = ((float) byteArrayToInt(buf, offset)) / 1000;
offset += 4;
data.vx = byteArrayToFloat(buf, offset);
offset += 4;
data.vy = byteArrayToFloat(buf, offset);
offset += 4;
data.vz = byteArrayToFloat(buf, offset);
offset += 4;
}
private static void parseState(NavData data, int state)
{
data.flying = (state & 1) != 0;
data.videoEnabled = (state & (1 << 1)) != 0;
data.visionEnabled = (state & (1 << 2)) != 0;
data.controlAlgorithm = (state & (1 << 3)) != 0 ? ControlAlgorithm.ANGULAR_SPEED_CONTROL
: ControlAlgorithm.EULER_ANGELS_CONTROL;
data.altitudeControlActive = (state & (1 << 4)) != 0;
data.userFeedbackOn = (state & (1 << 5)) != 0;
data.controlReceived = (state & (1 << 6)) != 0;
data.trimReceived = (state & (1 << 7)) != 0;
data.trimRunning = (state & (1 << 8)) != 0;
data.trimSucceeded = (state & (1 << 9)) != 0;
data.navDataDemoOnly = (state & (1 << 10)) != 0;
data.navDataBootstrap = (state & (1 << 11)) != 0;
data.motorsDown = (state & (1 << 12)) != 0;
data.gyrometersDown = (state & (1 << 14)) != 0;
data.batteryTooLow = (state & (1 << 15)) != 0;
data.batteryTooHigh = (state & (1 << 16)) != 0;
data.timerElapsed = (state & (1 << 17)) != 0;
data.notEnoughPower = (state & (1 << 18)) != 0;
data.angelsOutOufRange = (state & (1 << 19)) != 0;
data.tooMuchWind = (state & (1 << 20)) != 0;
data.ultrasonicSensorDeaf = (state & (1 << 21)) != 0;
data.cutoutSystemDetected = (state & (1 << 22)) != 0;
data.PICVersionNumberOK = (state & (1 << 23)) != 0;
data.ATCodedThreadOn = (state & (1 << 24)) != 0;
data.navDataThreadOn = (state & (1 << 25)) != 0;
data.videoThreadOn = (state & (1 << 26)) != 0;
data.acquisitionThreadOn = (state & (1 << 27)) != 0;
data.controlWatchdogDelayed = (state & (1 << 28)) != 0;
data.ADCWatchdogDelayed = (state & (1 << 29)) != 0;
data.communicationProblemOccurred = (state & (1 << 30)) != 0;
data.emergency = (state & (1 << 31)) != 0;
}
@SuppressWarnings("unused")
private static void printState(NavData data)
{
StringBuffer sb = new StringBuffer();
sb.append("IsFlying: " + data.isFlying() + "\n");
sb.append("IsVideoEnabled: " + data.isVideoEnabled() + "\n");
sb.append("IsVisionEnabled: " + data.isVisionEnabled() + "\n");
sb.append("controlAlgo: " + data.getControlAlgorithm() + "\n");
sb.append("AltitudeControlActive: " + data.isAltitudeControlActive() + "\n");
sb.append("IsUserFeedbackOn: " + data.isUserFeedbackOn() + "\n");
sb.append("ControlReceived: " + data.isVideoEnabled() + "\n");
sb.append("IsTrimReceived: " + data.isTrimReceived() + "\n");
sb.append("IsTrimRunning: " + data.isTrimRunning() + "\n");
sb.append("IsTrimSucceeded: " + data.isTrimSucceeded() + "\n");
sb.append("IsNavDataDemoOnly: " + data.isNavDataDemoOnly() + "\n");
sb.append("IsNavDataBootstrap: " + data.isNavDataBootstrap() + "\n");
sb.append("IsMotorsDown: " + data.isMotorsDown() + "\n");
sb.append("IsGyrometersDown: " + data.isGyrometersDown() + "\n");
sb.append("IsBatteryLow: " + data.isBatteryTooLow() + "\n");
sb.append("IsBatteryHigh: " + data.isBatteryTooHigh() + "\n");
sb.append("IsTimerElapsed: " + data.isTimerElapsed() + "\n");
sb.append("isNotEnoughPower: " + data.isNotEnoughPower() + "\n");
sb.append("isAngelsOutOufRange: " + data.isAngelsOutOufRange() + "\n");
sb.append("isTooMuchWind: " + data.isTooMuchWind() + "\n");
sb.append("isUltrasonicSensorDeaf: " + data.isUltrasonicSensorDeaf() + "\n");
sb.append("isCutoutSystemDetected: " + data.isCutoutSystemDetected() + "\n");
sb.append("isPICVersionNumberOK: " + data.isPICVersionNumberOK() + "\n");
sb.append("isATCodedThreadOn: " + data.isATCodedThreadOn() + "\n");
sb.append("isNavDataThreadOn: " + data.isNavDataThreadOn() + "\n");
sb.append("isVideoThreadOn: " + data.isVideoThreadOn() + "\n");
sb.append("isAcquisitionThreadOn: " + data.isAcquisitionThreadOn() + "\n");
sb.append("isControlWatchdogDelayed: " + data.isControlWatchdogDelayed() + "\n");
sb.append("isADCWatchdogDelayed: " + data.isADCWatchdogDelayed() + "\n");
sb.append("isCommunicationProblemOccurred: " + data.isCommunicationProblemOccurred() + "\n");
sb.append("IsEmergency: " + data.isEmergency() + "\n");
sb.append("CtrlState: " + data.getControlState() + "\n");
sb.append("Battery: " + data.getBattery() + "\n");
sb.append("Altidtude: " + data.getAltitude() + "\n");
sb.append("Pitch: " + data.getPitch() + "\n");
sb.append("Roll: " + data.getRoll() + "\n");
sb.append("Yaw: " + data.getYaw() + "\n");
sb.append("X velocity: " + data.getVx() + "\n");
sb.append("Y velocity: " + data.getLongitude() + "\n");
sb.append("Z velocity: " + data.getVz() + "\n");
sb.append("Vision Tags: " + data.getVisionTags() + "\n");
log.debug("State: " + sb.toString());
}
protected Mode mode;
// state flags
protected boolean flying;
protected boolean videoEnabled;
protected boolean visionEnabled;
protected ControlAlgorithm controlAlgorithm;
protected boolean altitudeControlActive;
protected boolean userFeedbackOn; // /TODO better
// name
protected boolean controlReceived;
protected boolean trimReceived;
protected boolean trimRunning;
protected boolean trimSucceeded;
protected boolean navDataDemoOnly;
protected boolean navDataBootstrap;
protected boolean motorsDown;
protected boolean gyrometersDown;
protected boolean batteryTooLow;
protected boolean batteryTooHigh;
protected boolean timerElapsed;
protected boolean notEnoughPower;
protected boolean angelsOutOufRange;
protected boolean tooMuchWind;
protected boolean ultrasonicSensorDeaf;
protected boolean cutoutSystemDetected;
protected boolean PICVersionNumberOK;
protected boolean ATCodedThreadOn;
protected boolean navDataThreadOn;
protected boolean videoThreadOn;
protected boolean acquisitionThreadOn;
protected boolean controlWatchdogDelayed;
protected boolean ADCWatchdogDelayed;
protected boolean communicationProblemOccurred;
protected boolean emergency;
// Common nav data
protected int sequence;
// Demo nav data
protected CtrlState ctrl_state;
protected int battery;
protected float altitude;
protected float pitch;
protected float roll;
protected float yaw;
protected float vx;
protected float vy;
protected float vz;
// Vision tags data
protected List<VisionTag> vision_tags;
/**
*
* @return value in meters
*/
public float getAltitude()
{
return altitude;
}
public int getBattery()
{
return battery;
}
public ControlAlgorithm getControlAlgorithm()
{
return controlAlgorithm;
}
public CtrlState getControlState()
{
return ctrl_state;
}
public float getLongitude()
{
return vy;
}
public Mode getMode()
{
return mode;
}
/**
*
* @return value in degrees
*/
public float getPitch()
{
return pitch;
}
/**
*
* @return value in degrees
*/
public float getRoll()
{
return roll;
}
public int getSequence()
{
return sequence;
}
public float getVx()
{
return vx;
}
public float getVz()
{
return vz;
}
/**
*
* @return value in degrees
*/
public float getYaw()
{
return yaw;
}
public boolean isAcquisitionThreadOn()
{
return acquisitionThreadOn;
}
public boolean isADCWatchdogDelayed()
{
return ADCWatchdogDelayed;
}
public boolean isAltitudeControlActive()
{
return altitudeControlActive;
}
public boolean isAngelsOutOufRange()
{
return angelsOutOufRange;
}
public boolean isATCodedThreadOn()
{
return ATCodedThreadOn;
}
public boolean isBatteryTooHigh()
{
return batteryTooHigh;
}
public boolean isBatteryTooLow()
{
return batteryTooLow;
}
public boolean isCommunicationProblemOccurred()
{
return communicationProblemOccurred;
}
public boolean isControlReceived()
{
return controlReceived;
}
public boolean isControlWatchdogDelayed()
{
return controlWatchdogDelayed;
}
public boolean isCutoutSystemDetected()
{
return cutoutSystemDetected;
}
public boolean isEmergency()
{
return emergency;
}
public boolean isFlying()
{
return flying;
}
public boolean isGyrometersDown()
{
return gyrometersDown;
}
public boolean isMotorsDown()
{
return motorsDown;
}
public boolean isNavDataBootstrap()
{
return navDataBootstrap;
}
public boolean isNavDataDemoOnly()
{
return navDataDemoOnly;
}
public boolean isNavDataThreadOn()
{
return navDataThreadOn;
}
public boolean isNotEnoughPower()
{
return notEnoughPower;
}
public boolean isPICVersionNumberOK()
{
return PICVersionNumberOK;
}
public boolean isTimerElapsed()
{
return timerElapsed;
}
public boolean isTooMuchWind()
{
return tooMuchWind;
}
public boolean isTrimReceived()
{
return trimReceived;
}
public boolean isTrimRunning()
{
return trimRunning;
}
public boolean isTrimSucceeded()
{
return trimSucceeded;
}
public boolean isUltrasonicSensorDeaf()
{
return ultrasonicSensorDeaf;
}
public boolean isUserFeedbackOn()
{
return userFeedbackOn;
}
public boolean isVideoEnabled()
{
return videoEnabled;
}
public boolean isVideoThreadOn()
{
return videoThreadOn;
}
public boolean isVisionEnabled()
{
return visionEnabled;
}
public FlyingState getFlyingState()
{
return FlyingState.fromControlState(ctrl_state);
}
public List<VisionTag> getVisionTags()
{
return vision_tags;
}
public void setVisionTags(List<VisionTag> vision_tags)
{
this.vision_tags = vision_tags;
}
}
@@ -0,0 +1,13 @@
package com.codeminders.ardrone;
@SuppressWarnings("serial")
public class NavDataFormatException extends Exception
{
public NavDataFormatException(String why)
{
super(why);
}
}
@@ -0,0 +1,7 @@
package com.codeminders.ardrone;
public interface NavDataListener
{
void navDataReceived(NavData nd);
}
@@ -0,0 +1,45 @@
package com.codeminders.ardrone;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
public class NavDataReader extends DataReader {
private static final int BUFSIZE = 4096;
public NavDataReader(ARDrone drone, InetAddress drone_addr, int navdata_port) throws IOException
{
super(drone, drone_addr, navdata_port, BUFSIZE);
}
@Override
void handleReceivedMessageKey(SelectionKey key, ByteBuffer inbuf) throws Exception
{
if(key.isWritable())
{
byte[] trigger_bytes = {0x01, 0x00, 0x00, 0x00};
ByteBuffer trigger_buf = ByteBuffer.allocate(trigger_bytes.length);
trigger_buf.put(trigger_bytes);
trigger_buf.flip();
channel.write(trigger_buf);
channel.register(selector, SelectionKey.OP_READ);
} else if(key.isReadable())
{
inbuf.clear();
int len = channel.read(inbuf);
byte[] packet = new byte[len];
inbuf.flip();
inbuf.get(packet, 0, len);
NavData nd = NavData.createFromData(packet);
drone.navDataReceived(nd);
}
}
}
@@ -0,0 +1,36 @@
package com.codeminders.ardrone;
public class Point
{
private int x;
private int y;
public Point(int x, int y)
{
super();
this.x = x;
this.y = y;
}
public int getX()
{
return x;
}
public void setX(int x)
{
this.x = x;
}
public int getY()
{
return y;
}
public void setY(int y)
{
this.y = y;
}
}
@@ -0,0 +1,51 @@
package com.codeminders.ardrone;
import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import com.codeminders.ardrone.video.*;
public class VideoReader extends DataReader {
/**
* Image data buffer. It should be big enough to hold single full frame
* (encoded).
*/
private static final int BUFSIZE = 100 * 1024;
public VideoReader(ARDrone drone, InetAddress drone_addr, int video_port) throws IOException
{
super(drone, drone_addr, video_port, BUFSIZE);
}
@Override
void handleReceivedMessageKey(SelectionKey key, ByteBuffer inbuf)
throws Exception {
if(key.isWritable())
{
byte[] trigger_bytes = { 0x01, 0x00, 0x00, 0x00 };
ByteBuffer trigger_buf = ByteBuffer.allocate(trigger_bytes.length);
trigger_buf.put(trigger_bytes);
trigger_buf.flip();
channel.write(trigger_buf);
channel.register(selector, SelectionKey.OP_READ);
} else if(key.isReadable())
{
inbuf.clear();
int len = channel.read(inbuf);
if(len > 0)
{
inbuf.flip();
final BufferedVideoImage vi = new BufferedVideoImage();
vi.addImageStream(inbuf);
drone.videoFrameReceived(0, 0, vi.getWidth(), vi.getHeight(), vi.getJavaPixelData(), 0, vi.getWidth());
}
}
}
}
@@ -0,0 +1,150 @@
package com.codeminders.ardrone;
public class VisionTag
{
public VisionTag(VisionTagType type, Point position, Dimension dimensions, int distance)
{
super();
this.type = type;
this.position = position;
this.dimensions = dimensions;
this.distance = distance;
}
/**
* @brief Values for the detection type on drone cameras.
*/
public static enum VisionTagType
{
CAD_TYPE_HORIZONTL(0), /* Deprecated */
CAD_TYPE_VERTICAL(1), /* Deprecated */
CAD_TYPE_VISION(2), /* Detection of 2D horizontal tags on drone shells */
CAD_TYPE_NONE(3), /* Detection disabled */
CAD_TYPE_COCARDE(4), /* Detects a roundel under the drone */
CAD_TYPE_ORIENTED_COCARDE(5), /*
* Detects an oriented roundel under the
* drone
*/
CAD_TYPE_STRIPE(6), /* Detects a uniform stripe on the ground */
CAD_TYPE_H_COCARDE(7), /* Detects a roundel in front of the drone */
CAD_TYPE_H_ORIENTED_COCARDE(8), /*
* Detects an oriented roundel in front
* of the drone
*/
CAD_TYPE_STRIPE_V(9), CAD_TYPE_MULTIPLE_DETECTION_MODE(10), /*
* The drone
* uses
* several
* detections
* at the
* same time
*/
CAD_TYPE_NUM(11); /* Number of possible values for CAD_TYPE */
private int value;
private VisionTagType(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
public static VisionTagType fromInt(int v) throws NavDataFormatException
{
switch(v)
{
case 0:
return VisionTagType.CAD_TYPE_HORIZONTL;
case 1:
return VisionTagType.CAD_TYPE_VERTICAL;
case 2:
return VisionTagType.CAD_TYPE_VISION;
case 3:
return VisionTagType.CAD_TYPE_NONE;
case 4:
return VisionTagType.CAD_TYPE_COCARDE;
case 5:
return VisionTagType.CAD_TYPE_ORIENTED_COCARDE;
case 6:
return VisionTagType.CAD_TYPE_STRIPE;
case 7:
return VisionTagType.CAD_TYPE_H_COCARDE;
case 8:
return VisionTagType.CAD_TYPE_H_ORIENTED_COCARDE;
case 9:
return VisionTagType.CAD_TYPE_STRIPE_V;
case 10:
return VisionTagType.CAD_TYPE_MULTIPLE_DETECTION_MODE;
case 11:
return VisionTagType.CAD_TYPE_NUM;
default:
throw new NavDataFormatException("Invalid vision tag type " + v);
}
}
};
// Type of the detected tag #i ; see the CAD_TYPE enumeration.
private VisionTagType type;
/**
* X and Y coordinates of detected 2D-tag #i inside the picture, with (0, 0)
* being the top-left corner, and (1000, 1000) the right-bottom corner
* regardless the picture resolu- tion or the source camera.
*/
private Point position;
/**
* Width and height of the detection bounding-box (2D-tag #i), when
* applicable.
*/
private Dimension dimensions;
/**
* Distance from camera to detected 2D-tag #i in centimeters, when
* applicable.
*/
private int distance;
public VisionTagType getType()
{
return type;
}
public Point getPosition()
{
return position;
}
public Dimension getDimensions()
{
return dimensions;
}
public int getDistance()
{
return distance;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("VisionTag [type=");
builder.append(type);
builder.append(", position=");
builder.append(position);
builder.append(", dimensions=");
builder.append(dimensions);
builder.append(", distance=");
builder.append(distance);
builder.append("]");
return builder.toString();
}
}
@@ -0,0 +1,83 @@
package com.codeminders.ardrone.commands;
import java.io.UnsupportedEncodingException;
import com.codeminders.ardrone.DroneCommand;
public abstract class ATCommand extends DroneCommand
{
private String encodeParameter(Object p)
{
if(p instanceof Integer)
return p.toString();
if(p instanceof Float)
return Integer.toString(Float.floatToIntBits((Float) p));
if(p instanceof String)
return "\"" + p + "\"";
throw new IllegalArgumentException("Unsupported parameter type: " + p.getClass().getName() + " " + p);
}
public String getCommandString(int seq)
{
return "AT*" + getID() + "=" + seq + getParametersString() + "\r";
}
protected abstract String getID();
public byte[] getPacket(int seq)
{
try
{
return getCommandString(seq).getBytes("ASCII");
} catch(UnsupportedEncodingException e)
{
// never happens
return null;
}
}
protected abstract Object[] getParameters();
private String getParametersString()
{
StringBuffer sb = new StringBuffer();
for(Object p : getParameters())
{
sb.append(',').append(encodeParameter(p));
}
return sb.toString();
}
@Override
public int getPriority()
{
return MIN_PRIORITY;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append(getClass().getSimpleName());
builder.append(" [ID=");
builder.append(getID());
builder.append(", param=");
builder.append(getParametersString());
builder.append("]");
return builder.toString();
}
public boolean equals(Object obj)
{
if(obj == null || !(obj instanceof ATCommand))
return false;
ATCommand o = (ATCommand) obj;
return o.getCommandString(0).equals(getCommandString(0));
}
}
@@ -0,0 +1,25 @@
package com.codeminders.ardrone.commands;
public class ConfigureCommand extends ATCommand
{
protected String name;
protected String value;
public ConfigureCommand(String name, String value)
{
this.name = name;
this.value = value;
}
@Override
protected String getID()
{
return "CONFIG";
}
@Override
protected Object[] getParameters()
{
return new Object[] { name, value };
}
}
@@ -0,0 +1,25 @@
package com.codeminders.ardrone.commands;
public class ControlCommand extends ATCommand
{
protected int arg1;
protected int arg2;
public ControlCommand(int arg1, int arg2)
{
this.arg1 = arg1;
this.arg2 = arg2;
}
@Override
protected String getID()
{
return "CTRL";
}
@Override
protected Object[] getParameters()
{
return new Object[] { arg1, arg2 };
}
}
@@ -0,0 +1,9 @@
package com.codeminders.ardrone.commands;
public class EmergencyCommand extends RefCommand
{
public EmergencyCommand()
{
value |= (1<<8);
}
}
@@ -0,0 +1,16 @@
package com.codeminders.ardrone.commands;
public class FlatTrimCommand extends ATCommand
{
@Override
protected String getID()
{
return "FTRIM";
}
@Override
protected Object[] getParameters()
{
return new Object[] {};
}
}
@@ -0,0 +1,9 @@
package com.codeminders.ardrone.commands;
public class HoverCommand extends PCMDCommand
{
public HoverCommand()
{
super(true);
}
}
@@ -0,0 +1,23 @@
package com.codeminders.ardrone.commands;
public class KeepAliveCommand extends ATCommand
{
@Override
protected String getID()
{
return "COMWDG";
}
@Override
protected Object[] getParameters()
{
return new Object[] {};
}
@Override
public int getPriority()
{
return VERY_HIGH_PRIORITY;
}
}
@@ -0,0 +1,26 @@
package com.codeminders.ardrone.commands;
public class LandCommand extends RefCommand
{
public LandCommand()
{
// 9th bit set to 0
}
@Override
public int getPriority()
{
return HIGH_PRIORITY;
}
public boolean isSticky()
{
return true;
}
public String getCategory()
{
return LAND_TAKEOFF_CATEGORY;
}
}
@@ -0,0 +1,18 @@
package com.codeminders.ardrone.commands;
public class MoveCommand extends PCMDCommand
{
public MoveCommand(boolean combined_yaw_enabled,
float left_right_tilt,
float front_back_tilt,
float vertical_speed,
float angular_speed)
{
super(false);
this.combined_yaw_enabled = combined_yaw_enabled;
this.left_right_tilt = left_right_tilt;
this.front_back_tilt = front_back_tilt;
this.vertical_speed = vertical_speed;
this.angular_speed = angular_speed;
}
}
@@ -0,0 +1,37 @@
package com.codeminders.ardrone.commands;
public class PCMDCommand extends ATCommand
{
protected boolean hover;
protected boolean combined_yaw_enabled;
protected float left_right_tilt;
protected float front_back_tilt;
protected float vertical_speed;
protected float angular_speed;
protected PCMDCommand(boolean hover)
{
this.hover = hover;
}
@Override
protected String getID()
{
return "PCMD";
}
@Override
protected Object[] getParameters()
{
if(hover)
return new Object[] { 0, 0f, 0f, 0f, 0f };
// int mode = combined_yaw_enabled ? 1 : 0;
int mode = 1;
if(combined_yaw_enabled)
mode |= (1<<1);
return new Object[] { mode, left_right_tilt, front_back_tilt, vertical_speed, angular_speed };
}
}
@@ -0,0 +1,25 @@
package com.codeminders.ardrone.commands;
public class PlayAnimationCommand extends ATCommand
{
protected int animation_no;
protected int duration;
public PlayAnimationCommand(int animation_no, int duration)
{
this.animation_no = animation_no;
this.duration = duration;
}
@Override
protected String getID()
{
return "ANIM";
}
@Override
protected Object[] getParameters()
{
return new Object[] { animation_no, duration };
}
}
@@ -0,0 +1,27 @@
package com.codeminders.ardrone.commands;
public class PlayLEDCommand extends ATCommand
{
protected int animation_no;
protected float frequency;
protected int duration;
public PlayLEDCommand(int animation_no, float frequency, int duration)
{
this.animation_no = animation_no;
this.frequency = frequency;
this.duration = duration;
}
@Override
protected String getID()
{
return "LED";
}
@Override
protected Object[] getParameters()
{
return new Object[] { animation_no, frequency, duration };
}
}
@@ -0,0 +1,12 @@
package com.codeminders.ardrone.commands;
import com.codeminders.ardrone.DroneCommand;
public class QuitCommand extends DroneCommand
{
@Override
public int getPriority()
{
return MAX_PRIORITY;
}
}
@@ -0,0 +1,23 @@
package com.codeminders.ardrone.commands;
public class RefCommand extends ATCommand
{
protected int value;
protected RefCommand()
{
value |= (1 << 18) | (1 << 20) | (1 << 22) | (1 << 24) | (1 << 28) ;
}
@Override
protected String getID()
{
return "REF";
}
@Override
protected Object[] getParameters()
{
return new Object[] { value };
}
}
@@ -0,0 +1,19 @@
package com.codeminders.ardrone.commands;
public class TakeOffCommand extends RefCommand
{
public TakeOffCommand()
{
value |= (1<<9);
}
public boolean isSticky()
{
return true;
}
public String getCategory()
{
return LAND_TAKEOFF_CATEGORY;
}
}
@@ -0,0 +1,101 @@
package com.codeminders.ardrone.controllers;
import java.io.IOException;
import java.util.BitSet;
import com.codeminders.hidapi.*;
/**
* "Afterglow" controller for PS3
*
* @author lord
*
*/
public class AfterGlowController extends PS3Controller
{
private static final int VENDOR_ID = 3695;
private static final int PRODUCT_ID = 25346;
private static final int BUFSIZE = 32;
private static final int EXPECTED_BUFSIZE = 27;
public static boolean isA(HIDDeviceInfo hidDeviceInfo)
{
return(hidDeviceInfo.getVendor_id() == VENDOR_ID && hidDeviceInfo.getProduct_id() == PRODUCT_ID);
}
private byte[] buf = new byte[BUFSIZE];
public AfterGlowController() throws HIDDeviceNotFoundException, IOException
{
dev = HIDManager.getInstance().openById(VENDOR_ID, PRODUCT_ID, null);
dev.enableBlocking();
}
public AfterGlowController(HIDDeviceInfo hidDeviceInfo) throws IOException
{
dev = hidDeviceInfo.open();
dev.enableBlocking();
}
private int joystickCoordConv(byte b)
{
int v = b < 0 ? b + 256 : b;
return v - 128;
}
@Override
public synchronized PS3ControllerState read() throws IOException
{
int n = dev.read(buf);
if(n != EXPECTED_BUFSIZE)
{
throw new IOException("Received packed with unexpected size " + n);
}
BitSet bs = new BitSet(13);
for(int i = 0; i < 8; i++)
{
if((1 & (buf[0] >> i)) == 1)
bs.set(i);
}
for(int i = 0; i < 5; i++)
{
if((1 & (buf[1] >> i)) == 1)
bs.set(8 + i);
}
int i = 0;
boolean square = bs.get(i++);
boolean cross = bs.get(i++);
boolean circle = bs.get(i++);
boolean triangle = bs.get(i++);
boolean L1 = bs.get(i++);
boolean R1 = bs.get(i++);
boolean L2 = bs.get(i++);
boolean R2 = bs.get(i++);
boolean select = bs.get(i++);
boolean start = bs.get(i++);
boolean leftJoystickPress = bs.get(i++);
boolean rightJoystickPress = bs.get(i++);
boolean PS = bs.get(i++);
int leftJoystickX = joystickCoordConv(buf[3]);
int leftJoystickY = joystickCoordConv(buf[4]);
int rightJoystickX = joystickCoordConv(buf[5]);
int rightJoystickY = joystickCoordConv(buf[6]);
// TODO: decode HAT switch
int hatSwitchLeftRight = 0;
int hatSwitchUpDown = 0;
PS3ControllerState res = new PS3ControllerState(square, cross, circle, triangle, L1, R1, L2, R2, select, start,
leftJoystickPress, rightJoystickPress, PS, hatSwitchLeftRight, hatSwitchUpDown, leftJoystickX,
leftJoystickY, rightJoystickX, rightJoystickY);
// System.err.println(res.toString());
return res;
}
}
@@ -0,0 +1,103 @@
package com.codeminders.ardrone.controllers;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import javax.swing.JFrame;
public class KeyboardController extends PS3Controller implements KeyListener
{
PS3ControllerState state = new PS3ControllerState();
public KeyboardController(JFrame frame)
{
frame.addKeyListener(this);
}
@Override
public PS3ControllerState read() throws IOException
{
PS3ControllerState s;
synchronized(state)
{
s = new PS3ControllerState(state);
}
return s;
}
@Override
public void keyPressed(KeyEvent e)
{
synchronized(state)
{
mapBooleanKey(e, true);
}
}
@Override
public void keyReleased(KeyEvent e)
{
synchronized(state)
{
mapBooleanKey(e, false);
}
}
private void mapBooleanKey(KeyEvent e, boolean value)
{
int c = e.getKeyCode();
switch(c)
{
case KeyEvent.VK_ENTER:
state.start = value;
break;
case KeyEvent.VK_SPACE:
state.select = value;
break;
case KeyEvent.VK_R:
state.PS = value;
break;
case KeyEvent.VK_C:
state.triangle = value;
break;
case KeyEvent.VK_F:
state.square = value;
break;
case KeyEvent.VK_E:
state.circle = value;
break;
case KeyEvent.VK_W:
state.leftJoystickY = value ? -127 : 0;
break;
case KeyEvent.VK_A:
state.leftJoystickX = value ? -127 : 0;
break;
case KeyEvent.VK_S:
state.leftJoystickY = value ? 127 : 0;
break;
case KeyEvent.VK_D:
state.leftJoystickX = value ? 127 : 0;
break;
case KeyEvent.VK_UP:
state.rightJoystickY = value ? -127 : 0;
break;
case KeyEvent.VK_LEFT:
state.rightJoystickX = value ? -127 : 0;
break;
case KeyEvent.VK_DOWN:
state.rightJoystickY = value ? 127 : 0;
break;
case KeyEvent.VK_RIGHT:
state.rightJoystickX = value ? 127 : 0;
break;
}
}
@Override
public void keyTyped(KeyEvent e)
{
}
}
@@ -0,0 +1,63 @@
package com.codeminders.ardrone.controllers;
import java.io.IOException;
import com.codeminders.hidapi.HIDDevice;
/**
* Base abstract class for supported PS3-compatible USB controllers
*
* @author lord
*
*/
public abstract class PS3Controller
{
protected HIDDevice dev;
protected static void printDelta(byte[] prev, int prev_size, byte[] cur, int cur_size)
{
if(prev_size != cur_size)
{
System.err.println("Packet size is different. Prev: " + prev_size + " New: " + cur_size);
return;
}
for(int i = 0; i < prev_size; i++)
{
if(prev[i] != cur[i])
{
System.err.println("Index: " + i + " Prev value: " + Integer.toHexString((int) prev[i])
+ " New value: " + Integer.toHexString((int) cur[i]));
}
}
}
public void close() throws IOException
{
if(dev != null)
dev.close();
}
public abstract PS3ControllerState read() throws IOException;
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("PS3Controller [");
try
{
builder.append("manufacturer=");
builder.append(dev.getManufacturerString());
builder.append(", product=");
builder.append(dev.getProductString());
} catch(IOException e)
{
builder.append("<invalid>");
}
builder.append("]");
return builder.toString();
}
}
@@ -0,0 +1,242 @@
package com.codeminders.ardrone.controllers;
/**
* Data structure describing state of generic PS-3 compatible game controller.
*
* @author lord
*/
public class PS3ControllerState
{
// buttons with pictures
protected boolean square;
protected boolean cross;
protected boolean circle;
protected boolean triangle;
// Front-side buttons
protected boolean L1;
protected boolean R1;
protected boolean L2;
protected boolean R2;
// square small "select" button
protected boolean select;
// triangular small "start" button
protected boolean start;
// Pressing on joysticks (button)
protected boolean leftJoystickPress;
protected boolean rightJoystickPress;
// PS3 button (sometimes labeled as Home on 3rd party models)
protected boolean PS;
// Direction pad (hatswitch)
protected int hatSwitchLeftRight;
protected int hatSwitchUpDown;
// Analog joysticks
protected int leftJoystickX;
protected int leftJoystickY;
protected int rightJoystickX;
protected int rightJoystickY;
public PS3ControllerState(boolean square, boolean cross, boolean circle, boolean triangle, boolean l1, boolean r1,
boolean l2, boolean r2, boolean select, boolean start, boolean leftJoystickPress,
boolean rightJoystickPress, boolean pS, int hatSwitchLeftRight, int hatSwitchUpDown, int leftJoystickX,
int leftJoystickY, int rightJoystickX, int rightJoystickY)
{
this.square = square;
this.cross = cross;
this.circle = circle;
this.triangle = triangle;
L1 = l1;
R1 = r1;
L2 = l2;
R2 = r2;
this.select = select;
this.start = start;
this.leftJoystickPress = leftJoystickPress;
this.rightJoystickPress = rightJoystickPress;
PS = pS;
this.hatSwitchLeftRight = hatSwitchLeftRight;
this.hatSwitchUpDown = hatSwitchUpDown;
this.leftJoystickX = leftJoystickX;
this.leftJoystickY = leftJoystickY;
this.rightJoystickX = rightJoystickX;
this.rightJoystickY = rightJoystickY;
}
public PS3ControllerState(PS3ControllerState o)
{
this.square = o.square;
this.cross = o.cross;
this.circle = o.circle;
this.triangle = o.triangle;
L1 = o.L1;
R1 = o.R1;
L2 = o.L2;
R2 = o.R2;
this.select = o.select;
this.start = o.start;
this.leftJoystickPress = o.leftJoystickPress;
this.rightJoystickPress = o.rightJoystickPress;
PS = o.PS;
this.hatSwitchLeftRight = o.hatSwitchLeftRight;
this.hatSwitchUpDown = o.hatSwitchUpDown;
this.leftJoystickX = o.leftJoystickX;
this.leftJoystickY = o.leftJoystickY;
this.rightJoystickX = o.rightJoystickX;
this.rightJoystickY = o.rightJoystickY;
}
public PS3ControllerState()
{
}
public int getHatSwitchLeftRight()
{
return hatSwitchLeftRight;
}
public int getHatSwitchUpDown()
{
return hatSwitchUpDown;
}
public int getLeftJoystickX()
{
return leftJoystickX;
}
public int getLeftJoystickY()
{
return leftJoystickY;
}
public int getRightJoystickX()
{
return rightJoystickX;
}
public int getRightJoystickY()
{
return rightJoystickY;
}
public boolean isCircle()
{
return circle;
}
public boolean isCross()
{
return cross;
}
public boolean isL1()
{
return L1;
}
public boolean isL2()
{
return L2;
}
public boolean isLeftJoystickPress()
{
return leftJoystickPress;
}
public boolean isPS()
{
return PS;
}
public boolean isR1()
{
return R1;
}
public boolean isR2()
{
return R2;
}
public boolean isRightJoystickPress()
{
return rightJoystickPress;
}
public boolean isSelect()
{
return select;
}
public boolean isSquare()
{
return square;
}
public boolean isStart()
{
return start;
}
public boolean isTriangle()
{
return triangle;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("PS3ControllerState [square=");
builder.append(square);
builder.append(", cross=");
builder.append(cross);
builder.append(", circle=");
builder.append(circle);
builder.append(", triangle=");
builder.append(triangle);
builder.append(", L1=");
builder.append(L1);
builder.append(", R1=");
builder.append(R1);
builder.append(", L2=");
builder.append(L2);
builder.append(", R2=");
builder.append(R2);
builder.append(", select=");
builder.append(select);
builder.append(", start=");
builder.append(start);
builder.append(", rightJoystickPress=");
builder.append(rightJoystickPress);
builder.append(", leftJoystickPress=");
builder.append(leftJoystickPress);
builder.append(", PS=");
builder.append(PS);
builder.append(", hatSwitchLeftRight=");
builder.append(hatSwitchLeftRight);
builder.append(", hatSwitchUpDown=");
builder.append(hatSwitchUpDown);
builder.append(", leftJoystickX=");
builder.append(leftJoystickX);
builder.append(", leftJoystickY=");
builder.append(leftJoystickY);
builder.append(", rightJoystickX=");
builder.append(rightJoystickX);
builder.append(", rightJoystickY=");
builder.append(rightJoystickY);
builder.append("]");
return builder.toString();
}
}
@@ -0,0 +1,207 @@
package com.codeminders.ardrone.controllers;
public class PS3ControllerStateChange extends PS3ControllerState
{
protected boolean squareChanged;
protected boolean crossChanged;
protected boolean circleChanged;
protected boolean triangleChanged;
protected boolean L1Changed;
protected boolean R1Changed;
protected boolean L2Changed;
protected boolean R2Changed;
protected boolean selectChanged;
protected boolean startChanged;
protected boolean leftJoystickPressChanged;
protected boolean rightJoystickPressChanged;
protected boolean PSChanged;
protected int hatSwitchLeftRightChange;
protected int hatSwitchUpDownChange;
protected int leftJoystickXChange;
protected int leftJoystickYChange;
protected int rightJoystickXChange;
protected int rightJoystickYChange;
// composite change flags
private boolean buttonStateChanged;
private boolean hatChanged;
private boolean leftJoystickChanged;
private boolean rightJoystickChanged;
private boolean joysticksChanged;
private boolean changed;
/**
*
* @param o Old state
* @param n New state
*/
public PS3ControllerStateChange(PS3ControllerState o, PS3ControllerState n)
{
super(n);
if(o==null)
o=n;
squareChanged = o.square != n.square;
crossChanged = o.cross != n.cross;
circleChanged = o.circle != n.circle;
triangleChanged = o.triangle != n.triangle;
L1Changed = o.L1 != n.L1;
R1Changed = o.R1 != n.R1;
L2Changed = o.L2 != n.L2;
R2Changed = o.R2 != n.R2;
selectChanged = o.select != n.select;
startChanged = o.start != n.start;
leftJoystickPressChanged = o.leftJoystickPress != n.leftJoystickPress;
rightJoystickPressChanged = o.rightJoystickPress != n.rightJoystickPress;
PSChanged = o.PS != n.PS;
hatSwitchLeftRightChange = n.hatSwitchLeftRight - o.hatSwitchLeftRight;
hatSwitchUpDownChange = n.hatSwitchUpDown - o.hatSwitchUpDown;
leftJoystickXChange = n.leftJoystickX - o.leftJoystickX;
leftJoystickYChange = n.leftJoystickY - o.leftJoystickY;
rightJoystickXChange = n.rightJoystickX - o.rightJoystickX;
rightJoystickYChange = n.rightJoystickY - o.rightJoystickY;
buttonStateChanged = squareChanged || crossChanged || circleChanged || triangleChanged || L1Changed
|| R1Changed || L2Changed || R2Changed || selectChanged || startChanged || leftJoystickPressChanged
|| rightJoystickPressChanged || PSChanged;
hatChanged = hatSwitchLeftRightChange != 0 || hatSwitchUpDownChange != 0;
leftJoystickChanged = leftJoystickXChange != 0 || leftJoystickYChange != 0;
rightJoystickChanged = rightJoystickXChange != 0 || rightJoystickYChange != 0;
joysticksChanged = leftJoystickChanged || rightJoystickChanged;
changed = joysticksChanged || hatChanged || buttonStateChanged;
}
public int getHatSwitchLeftRightChange()
{
return hatSwitchLeftRightChange;
}
public int getHatSwitchUpDownChange()
{
return hatSwitchUpDownChange;
}
public int getLeftJoystickXChange()
{
return leftJoystickXChange;
}
public int getLeftJoystickYChange()
{
return leftJoystickYChange;
}
public int getRightJoystickXChange()
{
return rightJoystickXChange;
}
public int getRightJoystickYChange()
{
return rightJoystickYChange;
}
public boolean isButtonStateChanged()
{
return buttonStateChanged;
}
public boolean isChanged()
{
return changed;
}
public boolean isCircleChanged()
{
return circleChanged;
}
public boolean isCrossChanged()
{
return crossChanged;
}
public boolean isHatChanged()
{
return hatChanged;
}
public boolean isJoysticksChanged()
{
return joysticksChanged;
}
public boolean isL1Changed()
{
return L1Changed;
}
public boolean isL2Changed()
{
return L2Changed;
}
public boolean isLeftJoystickChanged()
{
return leftJoystickChanged;
}
public boolean isLeftJoystickPressChanged()
{
return leftJoystickPressChanged;
}
public boolean isPSChanged()
{
return PSChanged;
}
public boolean isR1Changed()
{
return R1Changed;
}
public boolean isR2Changed()
{
return R2Changed;
}
public boolean isRightJoystickChanged()
{
return rightJoystickChanged;
}
public boolean isRightJoystickPressChanged()
{
return rightJoystickPressChanged;
}
public boolean isSelectChanged()
{
return selectChanged;
}
public boolean isSquareChanged()
{
return squareChanged;
}
public boolean isStartChanged()
{
return startChanged;
}
public boolean isTriangleChanged()
{
return triangleChanged;
}
}
@@ -0,0 +1,118 @@
package com.codeminders.ardrone.controllers;
import java.io.IOException;
import com.codeminders.hidapi.*;
import java.util.BitSet;
import org.apache.log4j.Logger;
public class SonyPS3Controller extends PS3Controller
{
private static final int VENDOR_ID = 1356;
private static final int PRODUCT_ID = 616;
private static final int BUFSIZE = 64;
private static final int EXPECTED_BUFSIZE = 32;
private static final int EXPECTED_BUFSIZE_2 = 49;
private byte[] buf = new byte[BUFSIZE];
public static boolean isA(HIDDeviceInfo hidDeviceInfo)
{
return(hidDeviceInfo.getVendor_id() == VENDOR_ID && hidDeviceInfo.getProduct_id() == PRODUCT_ID);
}
public SonyPS3Controller() throws HIDDeviceNotFoundException, IOException
{
dev = HIDManager.getInstance().openById(VENDOR_ID, PRODUCT_ID, null);
if (null != dev) {
dev.enableBlocking();
} else {
throw new HIDDeviceNotFoundException("Device not found");
}
}
public SonyPS3Controller(HIDDeviceInfo hidDeviceInfo) throws IOException
{
dev = hidDeviceInfo.open();
if (null != dev) {
dev.enableBlocking();
} else {
throw new HIDDeviceNotFoundException("Device not found");
}
// dev.close();
}
private int joystickCoordConv(byte b)
{
int v = b < 0 ? b + 256 : b;
return(v - 128);
}
@Override
public PS3ControllerState read() throws IOException
{
int n = dev.read(buf);
if(n != EXPECTED_BUFSIZE && n != EXPECTED_BUFSIZE_2)
{
throw new IOException("Received packed with unexpected size " + n);
}
BitSet bs = new BitSet(24);
for(int i = 0; i < 8; i++)
{
if((1 & (buf[2] >> i)) == 1)
bs.set(i);
}
for(int i = 0; i < 8; i++)
{
if((1 & (buf[3] >> i)) == 1)
bs.set(8 + i);
}
for(int i = 0; i < 8; i++)
{
if((1 & (buf[4] >> i)) == 1)
bs.set(16 + i);
}
int i = 0;
boolean select = bs.get(i++);
boolean leftJoystickPress = bs.get(i++);
boolean rightJoystickPress = bs.get(i++);
boolean start = bs.get(i++);
bs.get(i++);
bs.get(i++);
bs.get(i++);
bs.get(i++);
boolean L2 = bs.get(i++);
boolean R2 = bs.get(i++);
boolean R1 = bs.get(i++);
boolean L1 = bs.get(i++);
boolean triangle = bs.get(i++);
boolean circle = bs.get(i++);
boolean cross = bs.get(i++);
boolean square = bs.get(i++);
boolean PS = bs.get(i++);
int leftJoystickX = joystickCoordConv(buf[6]);
int leftJoystickY = joystickCoordConv(buf[7]);
int rightJoystickX = joystickCoordConv(buf[8]);
int rightJoystickY = joystickCoordConv(buf[9]);
// TODO: decode HAT switch
int hatSwitchLeftRight = 0;
int hatSwitchUpDown = 0;
PS3ControllerState res = new PS3ControllerState(square, cross, circle, triangle, L1, R1, L2, R2, select, start,
leftJoystickPress, rightJoystickPress, PS, hatSwitchLeftRight, hatSwitchUpDown, leftJoystickX,
leftJoystickY, rightJoystickX, rightJoystickY);
return res;
}
}
@@ -0,0 +1,53 @@
package com.codeminders.ardrone.examples;
import com.codeminders.ardrone.ARDrone;
public class TakeOffAndLand
{
private static final long CONNECT_TIMEOUT = 3000;
/**
* @param args
*/
public static void main(String[] args)
{
ARDrone drone;
try
{
// Create ARDrone object,
// connect to drone and initialize it.
drone = new ARDrone();
drone.connect();
drone.clearEmergencySignal();
// Wait until drone is ready
drone.waitForReady(CONNECT_TIMEOUT);
// do TRIM operation
drone.trim();
// Take off
System.err.println("Taking off");
drone.takeOff();
// Fly a little :)
Thread.sleep(5000);
// Land
System.err.println("Landing");
drone.land();
// Give it some time to land
Thread.sleep(2000);
// Disconnect from the done
drone.disconnect();
} catch(Throwable e)
{
e.printStackTrace();
}
}
}
@@ -0,0 +1,78 @@
package com.codeminders.ardrone.tools;
import java.io.IOException;
import com.codeminders.ardrone.controllers.*;
import com.codeminders.hidapi.ClassPathLibraryLoader;
import com.codeminders.hidapi.HIDDeviceInfo;
import com.codeminders.hidapi.HIDManager;
public class ControllerTest
{
private static final long READ_UPDATE_DELAY_MS = 30L;
static
{
ClassPathLibraryLoader.loadNativeHIDLibrary();
}
/**
* @param args
*/
public static void main(String[] args)
{
try
{
PS3Controller c = findController();
if(c == null)
{
System.err.println("Controller not found");
System.exit(1);
} else
{
System.err.println("Controller found "+c);
}
try
{
while(true)
{
PS3ControllerState x = c.read();
System.err.println(x);
try
{
Thread.sleep(READ_UPDATE_DELAY_MS);
} catch(InterruptedException e)
{
// Ignore
}
}
} finally
{
c.close();
}
} catch(IOException e)
{
e.printStackTrace();
}
}
private static PS3Controller findController() throws IOException
{
HIDDeviceInfo[] devs = HIDManager.getInstance().listDevices();
if (null != devs) {
for(int i = 0; i < devs.length; i++)
{
if(AfterGlowController.isA(devs[i]))
return new AfterGlowController(devs[i]);
if(SonyPS3Controller.isA(devs[i]))
return new SonyPS3Controller(devs[i]);
}
}
return null;
}
}
@@ -0,0 +1,152 @@
package com.codeminders.ardrone.tools;
import java.io.IOException;
import java.util.BitSet;
import com.codeminders.hidapi.*;
public class HIDAPITest
{
private static final long READ_UPDATE_DELAY_MS = 500L;
static
{
ClassPathLibraryLoader.loadNativeHIDLibrary();
}
private static final int BUFSIZE = 2048;
// "Afterglow" controller for PS3
// static final int VENDOR_ID = 3695;
// static final int PRODUCT_ID = 25346;
// Sony PLAYSTATION(R)3 Controller
static final int VENDOR_ID = 1356;
static final int PRODUCT_ID = 616;
/**
* @param args
*/
public static void main(String[] args)
{
listDevices();
readDevice();
}
private static void readDevice()
{
HIDDevice dev;
try
{
dev = HIDManager.getInstance().openById(VENDOR_ID, PRODUCT_ID, null);
System.err.print("Manufacturer: " + dev.getManufacturerString() + "\n");
System.err.print("Product: " + dev.getProductString() + "\n");
System.err.print("Serial Number: " + dev.getSerialNumberString() + "\n");
try
{
byte[] buf = new byte[BUFSIZE];
BitSet old = null;
dev.enableBlocking();
while(true)
{
int n = dev.read(buf);
if(n != 49)
{
System.err.println("Unexpected data packet size!");
return;
}
BitSet current = arrayToBitSet(buf, n);
if(old != null)
{
printHEX(buf, n);
printBitSetDiff(current, old);
}
old = current;
try
{
Thread.sleep(READ_UPDATE_DELAY_MS);
} catch(InterruptedException e)
{
// Ignore
}
}
} finally
{
dev.close();
}
} catch(IOException e)
{
e.printStackTrace();
}
}
private static void printBitSetDiff(BitSet current, BitSet old)
{
if(current.length() != old.length())
{
System.err.println("BitSet size does not match!");
return;
}
BitSet diff = (BitSet) current.clone();
diff.xor(old);
System.err.println(diff);
}
private static BitSet arrayToBitSet(byte[] buf, int n)
{
BitSet bs = new BitSet(n * 8);
for(int i = 0; i < n; i++)
{
byte b = buf[i];
for(int j = 0; j < 8; j++)
{
if((b & (1 << j)) > 0)
bs.set(i * 8 + j);
}
}
return bs;
}
private static void printHEX(byte[] buf, int n)
{
for(int i = 0; i < n; i++)
{
int v = buf[i];
if(v < 0)
v = v + 256;
String hs = Integer.toHexString(v);
if(v < 16)
System.err.print("0");
System.err.print(hs + " ");
}
System.err.println("");
}
private static void listDevices()
{
String property = System.getProperty("java.library.path");
System.err.println(property);
try
{
HIDDeviceInfo[] devs = HIDManager.getInstance().listDevices();
System.err.println("Devices:\n\n");
if (null != devs) {
for(int i = 0; i < devs.length; i++)
{
System.err.println("" + i + ".\t" + devs[i]);
System.err.println("---------------------------------------------\n");
}
}
} catch(IOException e)
{
System.err.println(e.getMessage());
e.printStackTrace();
}
}
}
@@ -0,0 +1,26 @@
package com.codeminders.ardrone.util;
import java.awt.image.BufferedImage;
import com.codeminders.ardrone.DroneVideoListener;
/**
* This is convenience base class for DroneVideoListener implementors, which
* presents video frames to user as instances of java.awt.image.BufferedImag
*
* @author lord
*/
public abstract class BufferedImageVideoListener implements DroneVideoListener
{
@Override
public void frameReceived(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
{
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
image.setRGB(startX, startY, w, h, rgbArray, offset, scansize);
imageReceived(image);
}
public abstract void imageReceived(BufferedImage image);
}
@@ -0,0 +1,111 @@
package com.codeminders.ardrone.util;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.imageio.ImageIO;
public class FileImageRecorder extends ImageVideoRecorderBase
{
private static final int MAX_SAVING_THREADS = 4;
private static final String EXT = ".png";
private boolean activated;
private ExecutorService executor;
public String getExtension()
{
return EXT;
}
private class ImageSaver implements Runnable
{
private BufferedImage image;
private FileImageRecorder recorder;
public ImageSaver(BufferedImage image, FileImageRecorder recorder)
{
this.image = image;
this.recorder = recorder;
}
@Override
public void run()
{
recorder.record(image);
}
}
/**
* Creates image recorder. It will record files in given directory with
* names like IMAGE-0010.png
*
* @param base_path - directory where image files will be stored
* @param starting_seq - starting sequence number
* @param prefix - filename prefix
* @param callback - callback object which will be notified on each
* success/failure. Could be null.
*/
public FileImageRecorder(File base_path, int starting_seq, String prefix, RecordingSuccessCallback callback)
{
super(base_path, starting_seq, prefix, callback);
this.activated = false;
executor = Executors.newFixedThreadPool(MAX_SAVING_THREADS);
}
void record(BufferedImage image)
{
File f;
try
{
f = openFile();
} catch(IOException e)
{
callback.recordingError(null, "error opening file", e);
return;
}
try
{
ImageIO.write(image, "png", f);
} catch(IOException e)
{
callback.recordingError(f.getPath(), "error writing file", e);
f.delete();
return;
}
callback.recordingSuccess(f.getPath());
}
/**
* Active recorder. Next image will be saved, after which it will be
* automatically deactivated.
*/
public synchronized void activate()
{
activated = true;
}
/**
* Active recorder.
*/
public synchronized void deActivate()
{
activated = false;
}
@Override
public synchronized void imageReceived(BufferedImage image)
{
if(!activated)
return;
executor.execute(new ImageSaver(image, this));
activated = false;
}
}
@@ -0,0 +1,160 @@
package com.codeminders.ardrone.util;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
/**
* Video recorder. It records single video file. You can start/stop recording
* many times.
*
* @author lord
*
*/
public class FileVideoRecorder extends ImageVideoRecorderBase implements Runnable
{
private static final String EXT = ".avi";
private Queue<BufferedImage> frames_queue = new LinkedList<BufferedImage>();
private boolean recording;
private boolean done;
private MJPEGGenerator generator;
double frame_rate;
private int frame_width;
private int frame_height;
File current_file;
public FileVideoRecorder(File base_path, int starting_seq, String prefix, RecordingSuccessCallback callback,
double frame_rate)
{
super(base_path, starting_seq, prefix, callback);
this.frame_rate = frame_rate;
this.recording = false;
this.done = false;
this.generator = null;
Thread thr = new Thread(this);
thr.start();
}
public synchronized void startRecording()
{
recording = true;
notify();
}
public synchronized void pauseRecording()
{
recording = false;
notify();
}
public synchronized void finishRecording()
{
recording = false;
done = true;
notify();
}
@Override
public synchronized void imageReceived(BufferedImage image)
{
if(recording)
{
frames_queue.add(image);
notify();
}
}
@Override
public synchronized void run()
{
while(true)
{
try
{
wait();
} catch(InterruptedException e)
{
// Ignore
}
if(done)
{
if(generator != null)
{
try
{
generator.finishAVI();
callback.recordingSuccess(current_file.getAbsolutePath());
} catch(Exception e)
{
callback.recordingError(current_file.getAbsolutePath(), "Error closing stream", e);
}
} else
{
callback.recordingError(null, "Recording have not started yet", null);
}
return;
}
BufferedImage frame = frames_queue.poll();
if(frame == null)
continue;
if(generator == null)
{
// Lazy init. Using first frame size as default
frame_width = frame.getWidth();
frame_height = frame.getHeight();
try
{
current_file = openFile();
} catch(IOException e1)
{
callback.recordingError(null, "Error opening file", e1);
return;
}
try
{
generator = new MJPEGGenerator(current_file, frame_width, frame_height, frame_rate, 0);
} catch(Exception e)
{
callback.recordingError(current_file.getAbsolutePath(), "Error video stream", e);
return;
}
}
try
{
if(frame.getWidth() != frame_width || frame.getHeight() != frame_height)
{
// Needs to be resized
Image i = frame.getScaledInstance(frame_width, frame_height, Image.SCALE_FAST);
generator.addImage(i);
} else
{
generator.addImage(frame);
}
} catch(Exception e)
{
callback.recordingError(current_file.getAbsolutePath(), "Error adding frame", e);
return;
}
}
}
public String getExtension()
{
return EXT;
}
}
@@ -0,0 +1,49 @@
package com.codeminders.ardrone.util;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
public abstract class ImageVideoRecorderBase extends BufferedImageVideoListener
{
private DecimalFormat format;
protected File base_path;
protected int seq;
protected String prefix;
protected RecordingSuccessCallback callback;
public ImageVideoRecorderBase(File base_path, int starting_seq, String prefix, RecordingSuccessCallback callback)
{
this.base_path = base_path;
this.seq = starting_seq;
this.prefix = prefix;
this.callback = callback;
format = new java.text.DecimalFormat("0000");
}
public abstract String getExtension();
protected File openFile() throws IOException
{
while(seq < 9999)
{
String fname = generateFileName();
File f = new File(base_path, fname);
if(f.createNewFile())
return f;
seq++;
continue;
}
throw new IOException("Filename space is exhausted. Could not create file");
}
private String generateFileName()
{
return prefix + format.format(new Integer(seq)) + getExtension();
}
}
@@ -0,0 +1,534 @@
/*
* MJPEGGenerator.java
*
* Created on April 17, 2006, 11:48 PM
*
* To change this template, choose Tools | Options and locate the template under
* the Source Creation and Management node. Right-click the template and choose
* Open. You can then make changes to the template in the Source Editor.
*/
package com.codeminders.ardrone.util;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.channels.FileChannel;
import java.util.*;
import javax.imageio.ImageIO;
/**
*
* @author monceaux
*/
public class MJPEGGenerator
{
/*
* Info needed for MJPEG AVI
*
* - size of file minus "RIFF & 4 byte file size"
*/
int width = 0;
int height = 0;
double framerate = 0;
int numFrames = 0;
File aviFile = null;
FileOutputStream aviOutput = null;
FileChannel aviChannel = null;
long riffOffset = 0;
long aviMovieOffset = 0;
AVIIndexList indexlist = null;
/** Creates a new instance of MJPEGGenerator */
public MJPEGGenerator(File aviFile, int width, int height, double framerate, int numFrames) throws Exception
{
this.aviFile = aviFile;
this.width = width;
this.height = height;
this.framerate = framerate;
this.numFrames = numFrames;
aviOutput = new FileOutputStream(aviFile);
aviChannel = aviOutput.getChannel();
RIFFHeader rh = new RIFFHeader();
aviOutput.write(rh.toBytes());
aviOutput.write(new AVIMainHeader().toBytes());
aviOutput.write(new AVIStreamList().toBytes());
aviOutput.write(new AVIStreamHeader().toBytes());
aviOutput.write(new AVIStreamFormat().toBytes());
aviOutput.write(new AVIJunk().toBytes());
aviMovieOffset = aviChannel.position();
aviOutput.write(new AVIMovieList().toBytes());
indexlist = new AVIIndexList();
}
public void addImage(Image image) throws Exception
{
byte[] fcc = new byte[] { '0', '0', 'd', 'b' };
byte[] imagedata = writeImageToBytes(image);
int useLength = imagedata.length;
long position = aviChannel.position();
int extra = (useLength + (int) position) % 4;
if(extra > 0)
useLength = useLength + extra;
indexlist.addAVIIndex((int) position, useLength);
aviOutput.write(fcc);
aviOutput.write(intBytes(swapInt(useLength)));
aviOutput.write(imagedata);
if(extra > 0)
{
for(int i = 0; i < extra; i++)
aviOutput.write(0);
}
imagedata = null;
}
public void finishAVI() throws Exception
{
byte[] indexlistBytes = indexlist.toBytes();
aviOutput.write(indexlistBytes);
aviOutput.close();
long size = aviFile.length();
RandomAccessFile raf = new RandomAccessFile(aviFile, "rw");
raf.seek(4);
raf.write(intBytes(swapInt((int) size - 8)));
raf.seek(aviMovieOffset + 4);
raf.write(intBytes(swapInt((int) (size - 8 - aviMovieOffset - indexlistBytes.length))));
raf.close();
}
// public void writeAVI(File file) throws Exception
// {
// OutputStream os = new FileOutputStream(file);
//
// // RIFFHeader
// // AVIMainHeader
// // AVIStreamList
// // AVIStreamHeader
// // AVIStreamFormat
// // write 00db and image bytes...
// }
public static int swapInt(int v)
{
return (v >>> 24) | (v << 24) | ((v << 8) & 0x00FF0000) | ((v >> 8) & 0x0000FF00);
}
public static short swapShort(short v)
{
return (short) ((v >>> 8) | (v << 8));
}
public static byte[] intBytes(int i)
{
byte[] b = new byte[4];
b[0] = (byte) (i >>> 24);
b[1] = (byte) ((i >>> 16) & 0x000000FF);
b[2] = (byte) ((i >>> 8) & 0x000000FF);
b[3] = (byte) (i & 0x000000FF);
return b;
}
public static byte[] shortBytes(short i)
{
byte[] b = new byte[2];
b[0] = (byte) (i >>> 8);
b[1] = (byte) (i & 0x000000FF);
return b;
}
private class RIFFHeader
{
public byte[] fcc = new byte[] { 'R', 'I', 'F', 'F' };
public int fileSize = 0;
public byte[] fcc2 = new byte[] { 'A', 'V', 'I', ' ' };
public byte[] fcc3 = new byte[] { 'L', 'I', 'S', 'T' };
public int listSize = 200;
public byte[] fcc4 = new byte[] { 'h', 'd', 'r', 'l' };
public RIFFHeader()
{
}
public byte[] toBytes() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(fileSize)));
baos.write(fcc2);
baos.write(fcc3);
baos.write(intBytes(swapInt(listSize)));
baos.write(fcc4);
baos.close();
return baos.toByteArray();
}
}
private class AVIMainHeader
{
/*
*
* FOURCC fcc; DWORD cb; DWORD dwMicroSecPerFrame; DWORD
* dwMaxBytesPerSec; DWORD dwPaddingGranularity; DWORD dwFlags; DWORD
* dwTotalFrames; DWORD dwInitialFrames; DWORD dwStreams; DWORD
* dwSuggestedBufferSize; DWORD dwWidth; DWORD dwHeight; DWORD
* dwReserved[4];
*/
public byte[] fcc = new byte[] { 'a', 'v', 'i', 'h' };
public int cb = 56;
public int dwMicroSecPerFrame = 0; // (1
// /
// frames
// per
// sec)
// *
// 1,000,000
public int dwMaxBytesPerSec = 10000000;
public int dwPaddingGranularity = 0;
public int dwFlags = 65552;
public int dwTotalFrames = 0; // replace
// with
// correct
// value
public int dwInitialFrames = 0;
public int dwStreams = 1;
public int dwSuggestedBufferSize = 0;
public int dwWidth = 0; // replace
// with
// correct
// value
public int dwHeight = 0; // replace
// with
// correct
// value
public int[] dwReserved = new int[4];
public AVIMainHeader()
{
dwMicroSecPerFrame = (int) ((1.0 / framerate) * 1000000.0);
dwWidth = width;
dwHeight = height;
dwTotalFrames = numFrames;
}
public byte[] toBytes() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(cb)));
baos.write(intBytes(swapInt(dwMicroSecPerFrame)));
baos.write(intBytes(swapInt(dwMaxBytesPerSec)));
baos.write(intBytes(swapInt(dwPaddingGranularity)));
baos.write(intBytes(swapInt(dwFlags)));
baos.write(intBytes(swapInt(dwTotalFrames)));
baos.write(intBytes(swapInt(dwInitialFrames)));
baos.write(intBytes(swapInt(dwStreams)));
baos.write(intBytes(swapInt(dwSuggestedBufferSize)));
baos.write(intBytes(swapInt(dwWidth)));
baos.write(intBytes(swapInt(dwHeight)));
baos.write(intBytes(swapInt(dwReserved[0])));
baos.write(intBytes(swapInt(dwReserved[1])));
baos.write(intBytes(swapInt(dwReserved[2])));
baos.write(intBytes(swapInt(dwReserved[3])));
baos.close();
return baos.toByteArray();
}
}
private class AVIStreamList
{
public byte[] fcc = new byte[] { 'L', 'I', 'S', 'T' };
public int size = 124;
public byte[] fcc2 = new byte[] { 's', 't', 'r', 'l' };
public AVIStreamList()
{
}
public byte[] toBytes() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(size)));
baos.write(fcc2);
baos.close();
return baos.toByteArray();
}
}
private class AVIStreamHeader
{
/*
* FOURCC fcc; DWORD cb; FOURCC fccType; FOURCC fccHandler; DWORD
* dwFlags; WORD wPriority; WORD wLanguage; DWORD dwInitialFrames; DWORD
* dwScale; DWORD dwRate; DWORD dwStart; DWORD dwLength; DWORD
* dwSuggestedBufferSize; DWORD dwQuality; DWORD dwSampleSize; struct {
* short int left; short int top; short int right; short int bottom; }
* rcFrame;
*/
public byte[] fcc = new byte[] { 's', 't', 'r', 'h' };
public int cb = 64;
public byte[] fccType = new byte[] { 'v', 'i', 'd', 's' };
public byte[] fccHandler = new byte[] { 'M', 'J', 'P', 'G' };
public int dwFlags = 0;
public short wPriority = 0;
public short wLanguage = 0;
public int dwInitialFrames = 0;
public int dwScale = 0; // microseconds
// per
// frame
public int dwRate = 1000000; // dwRate
// /
// dwScale
// =
// frame
// rate
public int dwStart = 0;
public int dwLength = 0; // num
// frames
public int dwSuggestedBufferSize = 0;
public int dwQuality = -1;
public int dwSampleSize = 0;
public int left = 0;
public int top = 0;
public int right = 0;
public int bottom = 0;
public AVIStreamHeader()
{
dwScale = (int) ((1.0 / framerate) * 1000000.0);
dwLength = numFrames;
}
public byte[] toBytes() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(cb)));
baos.write(fccType);
baos.write(fccHandler);
baos.write(intBytes(swapInt(dwFlags)));
baos.write(shortBytes(swapShort(wPriority)));
baos.write(shortBytes(swapShort(wLanguage)));
baos.write(intBytes(swapInt(dwInitialFrames)));
baos.write(intBytes(swapInt(dwScale)));
baos.write(intBytes(swapInt(dwRate)));
baos.write(intBytes(swapInt(dwStart)));
baos.write(intBytes(swapInt(dwLength)));
baos.write(intBytes(swapInt(dwSuggestedBufferSize)));
baos.write(intBytes(swapInt(dwQuality)));
baos.write(intBytes(swapInt(dwSampleSize)));
baos.write(intBytes(swapInt(left)));
baos.write(intBytes(swapInt(top)));
baos.write(intBytes(swapInt(right)));
baos.write(intBytes(swapInt(bottom)));
baos.close();
return baos.toByteArray();
}
}
private class AVIStreamFormat
{
/*
* FOURCC fcc; DWORD cb; DWORD biSize; LONG biWidth; LONG biHeight; WORD
* biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage;
* LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD
* biClrImportant;
*/
public byte[] fcc = new byte[] { 's', 't', 'r', 'f' };
public int cb = 40;
public int biSize = 40; // same
// as
// cb
public int biWidth = 0;
public int biHeight = 0;
public short biPlanes = 1;
public short biBitCount = 24;
public byte[] biCompression = new byte[] { 'M', 'J', 'P', 'G' };
public int biSizeImage = 0; // width
// x
// height
// in
// pixels
public int biXPelsPerMeter = 0;
public int biYPelsPerMeter = 0;
public int biClrUsed = 0;
public int biClrImportant = 0;
public AVIStreamFormat()
{
biWidth = width;
biHeight = height;
biSizeImage = width * height;
}
public byte[] toBytes() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(cb)));
baos.write(intBytes(swapInt(biSize)));
baos.write(intBytes(swapInt(biWidth)));
baos.write(intBytes(swapInt(biHeight)));
baos.write(shortBytes(swapShort(biPlanes)));
baos.write(shortBytes(swapShort(biBitCount)));
baos.write(biCompression);
baos.write(intBytes(swapInt(biSizeImage)));
baos.write(intBytes(swapInt(biXPelsPerMeter)));
baos.write(intBytes(swapInt(biYPelsPerMeter)));
baos.write(intBytes(swapInt(biClrUsed)));
baos.write(intBytes(swapInt(biClrImportant)));
baos.close();
return baos.toByteArray();
}
}
private class AVIMovieList
{
public byte[] fcc = new byte[] { 'L', 'I', 'S', 'T' };
public int listSize = 0;
public byte[] fcc2 = new byte[] { 'm', 'o', 'v', 'i' };
// 00db size jpg image data ...
public AVIMovieList()
{
}
public byte[] toBytes() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(listSize)));
baos.write(fcc2);
baos.close();
return baos.toByteArray();
}
}
private class AVIIndexList
{
public byte[] fcc = new byte[] { 'i', 'd', 'x', '1' };
public int cb = 0;
public List<AVIIndex> ind = new ArrayList<AVIIndex>();
public AVIIndexList()
{
}
@SuppressWarnings("unused")
public void addAVIIndex(AVIIndex ai)
{
ind.add(ai);
}
public void addAVIIndex(int dwOffset, int dwSize)
{
ind.add(new AVIIndex(dwOffset, dwSize));
}
public byte[] toBytes() throws Exception
{
cb = 16 * ind.size();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(cb)));
for(int i = 0; i < ind.size(); i++)
{
AVIIndex in = (AVIIndex) ind.get(i);
baos.write(in.toBytes());
}
baos.close();
return baos.toByteArray();
}
}
private class AVIIndex
{
public byte[] fcc = new byte[] { '0', '0', 'd', 'b' };
public int dwFlags = 16;
public int dwOffset = 0;
public int dwSize = 0;
public AVIIndex(int dwOffset, int dwSize)
{
this.dwOffset = dwOffset;
this.dwSize = dwSize;
}
public byte[] toBytes() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(dwFlags)));
baos.write(intBytes(swapInt(dwOffset)));
baos.write(intBytes(swapInt(dwSize)));
baos.close();
return baos.toByteArray();
}
}
private class AVIJunk
{
public byte[] fcc = new byte[] { 'J', 'U', 'N', 'K' };
public int size = 1808;
public byte[] data = new byte[size];
public AVIJunk()
{
Arrays.fill(data, (byte) 0);
}
public byte[] toBytes() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(size)));
baos.write(data);
baos.close();
return baos.toByteArray();
}
}
private byte[] writeImageToBytes(Image image) throws Exception
{
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Graphics2D g = bi.createGraphics();
g.drawImage(image, 0, 0, width, height, null);
ImageIO.write(bi, "jpg", baos);
baos.close();
bi = null;
g = null;
return baos.toByteArray();
}
}
@@ -0,0 +1,23 @@
package com.codeminders.ardrone.util;
public interface RecordingSuccessCallback
{
/**
* This method will be called if file was successfully recorded
*
* @param filename - full path to recorded file
*/
public void recordingSuccess(String filename);
/**
* This method will be called if file recording failed
*
* @param filename - file name we attempted to record. Could be null.
* @param err - error message. Could be null.
* @param ex - throwable, which caused the error. Could be null.
*/
public void recordingError(String filename, String err, Throwable ex);
}
@@ -0,0 +1,987 @@
package com.codeminders.ardrone.video;
import java.nio.ByteBuffer;
// Copyright (C) 2007-2011, PARROT SA, all rights reserved.
// DISCLAIMER
// The APIs is provided by PARROT and contributors "AS IS" and any express or
// implied warranties, including, but not limited to, the implied warranties of
// merchantability
// and fitness for a particular purpose are disclaimed. In no event shall PARROT
// and contributors be liable for any direct, indirect, incidental, special,
// exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or business
// interruption) however
// caused and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of the use
// of this
// software, even if advised of the possibility of such damage.
// Author : Daniel Schmidt
// Publishing date : 2010-01-06
// based on work by : Wilke Jansoone
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions, the disclaimer and the original author of the source
// code.
// - Neither the name of the PixVillage Team, nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
public class BufferedVideoImage
{
private static final int BLOCK_WIDTH = 8;
private static final int CIF_WIDTH = 88;
private static final int CIG_HEIGHT = 72;
private static final int VGA_WIDTH = 160;
private static final int VGA_HEIGHT = 120;
private static final int TABLE_QUANTIZATION_MODE = 31;
private static final int FIX_0_298631336 = 2446;
private static final int FIX_0_390180644 = 3196;
private static final int FIX_0_541196100 = 4433;
private static final int FIX_0_765366865 = 6270;
private static final int FIX_0_899976223 = 7373;
private static final int FIX_1_175875602 = 9633;
private static final int FIX_1_501321110 = 12299;
private static final int FIX_1_847759065 = 15137;
private static final int FIX_1_961570560 = 16069;
private static final int FIX_2_053119869 = 16819;
private static final int FIX_2_562915447 = 20995;
private static final int FIX_3_072711026 = 25172;
private static final int BITS = 13;
private static final int PASS1_BITS = 1;
private static final int F1 = BITS - PASS1_BITS - 1;
private static final int F2 = BITS - PASS1_BITS;
private static final int F3 = BITS + PASS1_BITS + 3;
/**
* 176px x 144px
*/
private static final int CIF = 1;
/**
* 320px x 240px
*/
private static final int QVGA = 2;
private static final short[] ZIGZAG_POSITIONS = new short[] { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,
11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29,
22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63, };
// Cfr. Handbook of Data Compression - Page 529
// David Salomon
// Giovanni Motta
private static final short[] QUANTIZER_VALUES = new short[] { 3, 5, 7, 9, 11, 13, 15, 17, 5, 7, 9, 11, 13,
15, 17, 19, 7, 9, 11, 13, 15, 17, 19, 21, 9, 11, 13, 15, 17, 19, 21, 23, 11, 13, 15, 17, 19, 21, 23, 25,
13, 15, 17, 19, 21, 23, 25, 27, 15, 17, 19, 21, 23, 25, 27, 29, 17, 19, 21, 23, 25, 27, 29, 31 };
static byte[] CLZLUT = new byte[] { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
private static final int[] CROMA_QUADRANT_OFFSETS = new int[] { 0, 4, 32, 36 };
private short[] dataBlockBuffer = new short[64];
private uint streamField;
private int streamFieldBitIndex;
private int streamIndex;
private int sliceCount;
private boolean pictureComplete;
private int pictureFormat;
private int resolution;
private int pictureType;
private int quantizerMode;
private int frameIndex;
private int sliceIndex;
private int blockCount;
private int width;
private int height;
/**
* Length of one row of pixels in the destination image in bytes.
*/
private int pixelRowSize;
private ByteBuffer imageStream;
private ImageSlice imageSlice;
private uint[] pixelData;
private int[] javaPixelData;
public void addImageStream(ByteBuffer stream)
{
imageStream = stream;
processStream();
}
private void alignStreamData()
{
int alignedLength;
int actualLength;
actualLength = streamFieldBitIndex;
if(actualLength > 0)
{
alignedLength = (actualLength & ~7);
if(alignedLength != actualLength)
{
alignedLength += 0x08;
streamField.shiftLeftEquals(alignedLength - actualLength);
streamFieldBitIndex = alignedLength;
}
}
}
private void composeImageSlice()
{
int u, ug, ub;
int v, vg, vr;
int r, g, b;
int lumaElementIndex1 = 0;
int lumaElementIndex2 = 0;
int chromaOffset = 0;
int dataIndex1 = 0;
int dataIndex2 = 0;
int lumaElementValue1 = 0;
int lumaElementValue2 = 0;
int chromaBlueValue = 0;
int chromaRedValue = 0;
int[] pixelDataQuadrantOffsets = new int[] { 0, BLOCK_WIDTH, width * BLOCK_WIDTH,
(width * BLOCK_WIDTH) + BLOCK_WIDTH };
int imageDataOffset = (sliceIndex - 1) * width * 16;
for(MacroBlock macroBlock : imageSlice.MacroBlocks)
{
for(int verticalStep = 0; verticalStep < BLOCK_WIDTH / 2; verticalStep++)
{
chromaOffset = verticalStep * BLOCK_WIDTH;
lumaElementIndex1 = verticalStep * BLOCK_WIDTH * 2;
lumaElementIndex2 = lumaElementIndex1 + BLOCK_WIDTH;
dataIndex1 = imageDataOffset + (2 * verticalStep * width);
dataIndex2 = dataIndex1 + width;
for(int horizontalStep = 0; horizontalStep < BLOCK_WIDTH / 2; horizontalStep++)
{
for(int quadrant = 0; quadrant < 4; quadrant++)
{
int chromaIndex = chromaOffset + CROMA_QUADRANT_OFFSETS[quadrant] + horizontalStep;
chromaBlueValue = macroBlock.DataBlocks[4][chromaIndex];
chromaRedValue = macroBlock.DataBlocks[5][chromaIndex];
u = chromaBlueValue - 128;
ug = 88 * u;
ub = 454 * u;
v = chromaRedValue - 128;
vg = 183 * v;
vr = 359 * v;
for(int pixel = 0; pixel < 2; pixel++)
{
int deltaIndex = 2 * horizontalStep + pixel;
lumaElementValue1 = macroBlock.DataBlocks[quadrant][lumaElementIndex1 + deltaIndex] << 8;
lumaElementValue2 = macroBlock.DataBlocks[quadrant][lumaElementIndex2 + deltaIndex] << 8;
r = saturate5(lumaElementValue1 + vr);
g = saturate6(lumaElementValue1 - ug - vg);
b = saturate5(lumaElementValue1 + ub);
int index1 = dataIndex1 + pixelDataQuadrantOffsets[quadrant] + deltaIndex;
pixelData[index1] = makeRGB(r, g, b);
javaPixelData[index1] = pixelData[index1].intValue();
r = saturate5(lumaElementValue2 + vr);
g = saturate6(lumaElementValue2 - ug - vg);
b = saturate5(lumaElementValue2 + ub);
int index2 = dataIndex2 + pixelDataQuadrantOffsets[quadrant] + deltaIndex;
pixelData[index2] = makeRGB(r, g, b);
javaPixelData[index2] = pixelData[index2].intValue();
}
}
}
}
imageDataOffset += 16;
}
}
private static int countLeadingZeros(uint value)
{
int accum = 0;
accum += CLZLUT[value.shiftRight(24).intValue()];
if(accum == 8)
accum += CLZLUT[(value.shiftRight(16).intValue()) & 0xFF];
if(accum == 16)
accum += CLZLUT[(value.shiftRight(8).intValue()) & 0xFF];
if(accum == 24)
accum += CLZLUT[value.intValue() & 0xFF];
return accum;
}
private void decodeFieldBytes(int[] run, int[] level, boolean[] last)
{
uint streamCode = new uint(0);
int streamLength = 0;
;
int zeroCount = 0;
int temp = 0;
int sign = 0;
// Use the RLE and Huffman dictionaries to understand this code
// fragment. You can find
// them in the developers guide on page 34.
// The bits in the data are actually composed of two kinds of fields:
// - run fields - this field contains information on the number of
// consecutive zeros.
// - level fields - this field contains the actual non zero value which
// can be negative or positive.
// First we extract the run field info and then the level field info.
streamCode = peekStreamData(imageStream, 32);
// Determine number of consecutive zeros in zig zag. (a.k.a
// 'run' field info)
// Suppose we have following bit sequence:
// 00001111.....
// 1 - Count the number of leading zeros -> 4
// Coarse value lookup is thus 00001
// 2 - Lookup the additional value, for coarse value 00001 this is 3
// addtional bits
// 3 - Calculate value of run, for coarse value 00001 this is (111) + 8
zeroCount = countLeadingZeros(streamCode); // - (1)
streamCode.shiftLeftEquals(zeroCount + 1); // - (2) -> shift left to get
// rid of the coarse value
streamLength += zeroCount + 1; // - position bit pointer to keep track
// off how many bits to consume later on
// the stream.
if(zeroCount > 1)
{
temp = (streamCode.shiftRight(32 - (zeroCount - 1))).intValue(); // -
// (2)
// ->
// shift
// right
// to
// determine
// the
// addtional
// bits
// (number
// of
// additional
// bits
// is
// zerocount
// - 1)
streamCode.shiftLeftEquals(zeroCount - 1); // - shift all of the run
// bits out of the way
// so the first bit is
// points to the first
// bit of the level
// field.
streamLength += zeroCount - 1;// - position bit pointer to keep
// track off how many bits to
// consume later on the stream.
run[0] = temp + (1 << (zeroCount - 1)); // - (3) -> calculate run
// value
} else
{
run[0] = zeroCount;
}
// Determine non zero value. (a.k.a 'level' field info)
// Suppose we have following bit sequence:
// 000011111.....
// 1 - Count the number of leading zeros -> 4
// Coarse value lookup is thus 00001
// 2 - Lookup the additional value, for coarse value 00001 this is 4
// addtional bits (last bit is sign bit)
// 3 - Calculate value of run, for coarse value 00001 this is (xxx) + 8,
// multiply by sign
zeroCount = countLeadingZeros(streamCode);
streamCode.shiftLeftEquals(zeroCount + 1); // - (1)
streamLength += zeroCount + 1; // - position bit pointer to keep track
// off how many bits to consume later on
// the stream.
if(zeroCount == 1)
{
// If coarse value is 01 according to the Huffman dictionary this
// means EOB, so there is
// no run and level and we indicate this by setting last to true;
run[0] = 0;
last[0] = true;
} else
{
if(zeroCount == 0)
{
zeroCount = 1;
temp = 1;
}
streamLength += zeroCount;// - position bit pointer to keep track
// off how many bits to consume later on
// the stream.
streamCode.shiftRightEquals(32 - zeroCount);// - (2) -> shift right
// to determine the
// addtional bits
// (number of additional
// bits is zerocount)
// sign = (sbyte)(streamCode & 1); // determine sign, last bit is
// sign
sign = (int) (streamCode.and(1).intValue()); // determine sign, last
// bit is sign
if(zeroCount != 0)
{
// temp = (sbyte)(streamCode >> 1); // take into account that
// last bit is sign, so shift it out of the way
// temp += (sbyte)(1 << (zeroCount - 1)); // - (3) -> calculate
// run value without sign
temp = (streamCode.shiftRight(1)).intValue(); // take into
// account
// that last bit is
// sign, so shift it
// out of the way
temp += (int) (1 << (zeroCount - 1)); // - (3) -> calculate run
// value without sign
}
level[0] = (sign == 1) ? -temp : temp; // - (3) -> calculate run
// value with sign
last[0] = false;
}
readStreamData(streamLength);
}
private void getBlockBytes(boolean acCoefficientsAvailable)
{
int[] run = new int[] { 0 };
int[] level = new int[] { 0 };
int zigZagPosition = 0;
int matrixPosition = 0;
boolean[] last = new boolean[] { false };
for(int i = 0; i < dataBlockBuffer.length; i++)
dataBlockBuffer[i] = 0;
uint dcCoefficient = readStreamData(10);
if(quantizerMode == TABLE_QUANTIZATION_MODE)
{
dataBlockBuffer[0] = (short) (dcCoefficient.times(QUANTIZER_VALUES[0]));
if(acCoefficientsAvailable)
{
decodeFieldBytes(run, level, last);
while(!last[0])
{
zigZagPosition += run[0] + 1;
matrixPosition = ZIGZAG_POSITIONS[zigZagPosition];
level[0] *= QUANTIZER_VALUES[matrixPosition];
dataBlockBuffer[matrixPosition] = (short) level[0];
decodeFieldBytes(run, level, last);
}
}
} else
{
// Currently not implemented.
throw new RuntimeException("ant quantizer mode is not yet implemented.");
}
}
public int getFrameIndex()
{
return frameIndex;
}
public int getHeight()
{
return height;
}
public int[] getJavaPixelData()
{
return javaPixelData;
}
public int getPictureType()
{
return pictureType;
}
public uint[] getPixelData()
{
return pixelData;
}
public int getPixelRowSize()
{
return pixelRowSize;
}
public int getSliceCount()
{
return sliceCount;
}
public int getWidth()
{
return width;
}
void inverseTransform(int macroBlockIndex, int dataBlockIndex)
{
int[] workSpace = new int[64];
short[] data = new short[64];
int z1, z2, z3, z4, z5;
int tmp0, tmp1, tmp2, tmp3;
int tmp10, tmp11, tmp12, tmp13;
int pointer = 0;
for(int index = 8; index > 0; index--)
{
if(dataBlockBuffer[pointer + 8] == 0 && dataBlockBuffer[pointer + 16] == 0
&& dataBlockBuffer[pointer + 24] == 0 && dataBlockBuffer[pointer + 32] == 0
&& dataBlockBuffer[pointer + 40] == 0 && dataBlockBuffer[pointer + 48] == 0
&& dataBlockBuffer[pointer + 56] == 0)
{
int dcValue = dataBlockBuffer[pointer] << PASS1_BITS;
workSpace[pointer + 0] = dcValue;
workSpace[pointer + 8] = dcValue;
workSpace[pointer + 16] = dcValue;
workSpace[pointer + 24] = dcValue;
workSpace[pointer + 32] = dcValue;
workSpace[pointer + 40] = dcValue;
workSpace[pointer + 48] = dcValue;
workSpace[pointer + 56] = dcValue;
pointer++;
continue;
}
z2 = dataBlockBuffer[pointer + 16];
z3 = dataBlockBuffer[pointer + 48];
z1 = (z2 + z3) * FIX_0_541196100;
tmp2 = z1 + z3 * -FIX_1_847759065;
tmp3 = z1 + z2 * FIX_0_765366865;
z2 = dataBlockBuffer[pointer];
z3 = dataBlockBuffer[pointer + 32];
tmp0 = (z2 + z3) << BITS;
tmp1 = (z2 - z3) << BITS;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
tmp0 = dataBlockBuffer[pointer + 56];
tmp1 = dataBlockBuffer[pointer + 40];
tmp2 = dataBlockBuffer[pointer + 24];
tmp3 = dataBlockBuffer[pointer + 8];
z1 = tmp0 + tmp3;
z2 = tmp1 + tmp2;
z3 = tmp0 + tmp2;
z4 = tmp1 + tmp3;
z5 = (z3 + z4) * FIX_1_175875602;
tmp0 = tmp0 * FIX_0_298631336;
tmp1 = tmp1 * FIX_2_053119869;
tmp2 = tmp2 * FIX_3_072711026;
tmp3 = tmp3 * FIX_1_501321110;
z1 = z1 * -FIX_0_899976223;
z2 = z2 * -FIX_2_562915447;
z3 = z3 * -FIX_1_961570560;
z4 = z4 * -FIX_0_390180644;
z3 += z5;
z4 += z5;
tmp0 += z1 + z3;
tmp1 += z2 + z4;
tmp2 += z2 + z3;
tmp3 += z1 + z4;
workSpace[pointer + 0] = ((tmp10 + tmp3 + (1 << F1)) >> F2);
workSpace[pointer + 56] = ((tmp10 - tmp3 + (1 << F1)) >> F2);
workSpace[pointer + 8] = ((tmp11 + tmp2 + (1 << F1)) >> F2);
workSpace[pointer + 48] = ((tmp11 - tmp2 + (1 << F1)) >> F2);
workSpace[pointer + 16] = ((tmp12 + tmp1 + (1 << F1)) >> F2);
workSpace[pointer + 40] = ((tmp12 - tmp1 + (1 << F1)) >> F2);
workSpace[pointer + 24] = ((tmp13 + tmp0 + (1 << F1)) >> F2);
workSpace[pointer + 32] = ((tmp13 - tmp0 + (1 << F1)) >> F2);
pointer++;
}
pointer = 0;
for(int index = 0; index < 8; index++)
{
z2 = workSpace[pointer + 2];
z3 = workSpace[pointer + 6];
z1 = (z2 + z3) * FIX_0_541196100;
tmp2 = z1 + z3 * -FIX_1_847759065;
tmp3 = z1 + z2 * FIX_0_765366865;
tmp0 = (workSpace[pointer + 0] + workSpace[pointer + 4]) << BITS;
tmp1 = (workSpace[pointer + 0] - workSpace[pointer + 4]) << BITS;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
tmp0 = workSpace[pointer + 7];
tmp1 = workSpace[pointer + 5];
tmp2 = workSpace[pointer + 3];
tmp3 = workSpace[pointer + 1];
z1 = tmp0 + tmp3;
z2 = tmp1 + tmp2;
z3 = tmp0 + tmp2;
z4 = tmp1 + tmp3;
z5 = (z3 + z4) * FIX_1_175875602;
tmp0 = tmp0 * FIX_0_298631336;
tmp1 = tmp1 * FIX_2_053119869;
tmp2 = tmp2 * FIX_3_072711026;
tmp3 = tmp3 * FIX_1_501321110;
z1 = z1 * -FIX_0_899976223;
z2 = z2 * -FIX_2_562915447;
z3 = z3 * -FIX_1_961570560;
z4 = z4 * -FIX_0_390180644;
z3 += z5;
z4 += z5;
tmp0 += z1 + z3;
tmp1 += z2 + z4;
tmp2 += z2 + z3;
tmp3 += z1 + z4;
data[pointer + 0] = (short) ((tmp10 + tmp3) >> F3);
data[pointer + 7] = (short) ((tmp10 - tmp3) >> F3);
data[pointer + 1] = (short) ((tmp11 + tmp2) >> F3);
data[pointer + 6] = (short) ((tmp11 - tmp2) >> F3);
data[pointer + 2] = (short) ((tmp12 + tmp1) >> F3);
data[pointer + 5] = (short) ((tmp12 - tmp1) >> F3);
data[pointer + 3] = (short) ((tmp13 + tmp0) >> F3);
data[pointer + 4] = (short) ((tmp13 - tmp0) >> F3);
pointer += 8;
}
for(int i = 0; i < data.length; i++)
imageSlice.MacroBlocks[macroBlockIndex].DataBlocks[dataBlockIndex][i] = data[i];
}
private uint makeRGB(int r, int g, int b)
{
r <<= 2;
g <<= 1;
b <<= 2;
uint ru = new uint(r);
uint gu = new uint(g);
uint bu = new uint(b);
uint retval = ru.shiftLeft(16);
retval = retval.or(gu.shiftLeft(8));
retval = retval.or(bu);
return retval;
}
// Blockline:
// _______
// | 1 | 2 |
// |___|___| Y
// | 3 | 4 |
// |___|___|
// ___
// | 5 |
// |___| Cb
// ___
// | 6 |
// |___| Cr
//
// Layout in memory
// _______________________
// | 1 | 2 | 3 | 4 | 5 | 6 | ...
// |___|___|___|___|___|___|
//
// Example, suppose the six data sub blocks are as follows:
// ==============Y0============== ==============Y1==============
// ==============Y2============== ==============Y3==============
// 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
// 0, 1, 2, 3, 4, 5, 6, 7,
// 8, 9, 10, 11, 12, 13, 14, 15, 8, 9, 10, 11, 12, 13, 14, 15, 8, 9, 10, 11,
// 12, 13, 14, 15, 8, 9, 10, 11, 12, 13, 14, 15,
// 16, 17, 18, 19, 20, 21, 22, 23, 16, 17, 18, 19, 20, 21, 22, 23, 16, 17,
// 18, 19, 20, 21, 22, 23, 16, 17, 18, 19, 20, 21, 22, 23,
// 24, 25, 26, 27, 28, 29, 30, 31, 24, 25, 26, 27, 28, 29, 30, 31, 24, 25,
// 26, 27, 28, 29, 30, 31, 24, 25, 26, 27, 28, 29, 30, 31,
// 32, 33, 34, 35, 36, 37, 38, 39, 32, 33, 34, 35, 36, 37, 38, 39, 32, 33,
// 34, 35, 36, 37, 38, 39, 32, 33, 34, 35, 36, 37, 38, 39,
// 40, 41, 42, 43, 44, 45, 46, 47, 40, 41, 42, 43, 44, 45, 46, 47, 40, 41,
// 42, 43, 44, 45, 46, 47, 40, 41, 42, 43, 44, 45, 46, 47,
// 48, 49, 50, 51, 52, 53, 54, 55, 48, 49, 50, 51, 52, 53, 54, 55, 48, 49,
// 50, 51, 52, 53, 54, 55, 48, 49, 50, 51, 52, 53, 54, 55,
// 56, 57, 58, 59, 60, 61, 62, 63, 56, 57, 58, 59, 60, 61, 62, 63, 56, 57,
// 58, 59, 60, 61, 62, 63, 56, 57, 58, 59, 60, 61, 62, 63
// ==============Cb============== ==============Cr==============
// 0, 1, 2, 3, | 4, 5, 6, 7, 0, 1, 2, 3, | 4, 5, 6, 7,
// 8, 9, 10, 11, | 12, 13, 14, 15, 8, 9, 10, 11, | 12, 13, 14, 15,
// 16, 17, 18, 19, | 20, 21, 22, 23, 16, 17, 18, 19, | 20, 21, 22, 23,
// 24, 25, 26, 27, | 28, 29, 30, 31, 24, 25, 26, 27, | 28, 29, 30, 31,
// ----------------| --------------- --------------- | ---------------
// 32, 33, 34, 35, | 36, 37, 38, 39, 32, 33, 34, 35, | 36, 37, 38, 39,
// 40, 41, 42, 43, | 44, 45, 46, 47, 40, 41, 42, 43, | 44, 45, 46, 47,
// 48, 49, 50, 51, | 52, 53, 54, 55, 48, 49, 50, 51, | 52, 53, 54, 55,
// 56, 57, 58, 59, | 60, 61, 62, 63, 56, 57, 58, 59, | 60, 61, 62, 63,
// Pixel Matrix
// 0, 1, 2, 3, 4, 5, 6, 7, | 8, 9, 10, 11, 12, 13, 14, 15,
// 16, 17, 18, 19, 20, 21, 22, 23, | 24, 25, 26, 27, 28, 29, 30, 31,
// 32, 33, 34, 35, 36, 37, 38, 39, | 40, 41, 42, 43, 44, 45, 46, 47,
// 48, 49, 50, 51, 52, 53, 54, 55, | 56, 57, 58, 59, 60, 61, 62, 63,
// 64, 65, 66, 67, 68, 69, 70, 71, | 72, 73, 74, 75, 76, 77, 78, 79,
// 80, 81, 82, 83, 84, 85, 86, 87, | 88, 89, 90, 91, 92, 93, 94, 95,
// 96, 97, 98, 99, 100, 101, 102, 103, | 104, 105, 106, 107, 108, 109, 110,
// 111,
// 112, 113, 114, 115, 116, 117, 118, 119, | 120, 121, 122, 123, 124, 125,
// 126, 127,
// ----------------------------------------|---------------------------------------
// 128, 129, 130, 131, 132, 133, 134, 135, | 136, 137, 138, 139, 140, 141,
// 142, 143,
// 144, 145, 146, 147, 148, 149, 150, 151, | 152, 153, 154, 155, 156, 157,
// 158, 159,
// 160, 161, 162, 163, 164, 165, 166, 167, | 168, 169, 170, 171, 172, 173,
// 174, 175,
// 176, 177, 178, 179, 180, 181, 182, 183, | 184, 185, 186, 187, 188, 189,
// 190, 191,
// 192, 193, 194, 195, 196, 197, 198, 199, | 200, 201, 202, 203, 204, 205,
// 206, 207,
// 208, 209, 210, 211, 212, 213, 214, 215, | 216, 217, 218, 219, 220, 221,
// 222, 223,
// 224, 225, 226, 227, 228, 229, 230, 231, | 232, 233, 234, 235, 236, 237,
// 238, 239,
// 240, 241, 242, 243, 244, 245, 246, 247, | 248, 249, 250, 251, 252, 253,
// 254, 255,
// The four Luma 8x8 matrices (quadrants Y0, Y1, Y2, Y3) form the basis of
// the final 16x16 pixel matrix.
// The two Croma 8x8 matrices are used to calculate the actual RGB value of
// the pixel (RGB565, each pixel is represented by two bytes)
// Each processing loop processes from each Luma matrix two rows. In each
// 'two row' loop the rows are processed
// by two columns.
// First Loop will take (assume there is only one pixel matrix to fill):
// Quadrant 1
// From Cb -> 0
// From Cr -> 0
// From Y0 -> 0, 8 and 1, 9 - use Cb and Cr to calculate RGB and place in
// pixel matrix in 0, 16 and 1 and 17
// Quadrant 2
// From Cb -> 4
// From Cr -> 4
// From Y1 -> 0, 8 and 1, 9 - use Cb and Cr to calculate RGB and place in
// pixel matrix in 8, 24 and 9 and 25
// Quadrant 3
// From Cb -> 32
// From Cr -> 32
// From Y2 -> 0, 8 and 1, 9 - use Cb and Cr to calculate RGB and place in
// pixel matrix in 128, 144 and 129 and 145
// Quadrant 4
// From Cb -> 36
// From Cr -> 36
// From Y3 -> 0, 8 and 1, 9 - use Cb and Cr to calculate RGB and place in
// pixel matrix in 136, 152 and 137 and 153
// Second Loop will take (assume there is only one pixel matrix to fill):
// Quadrant 1
// From Cb -> 1
// From Cr -> 1
// From Y0 -> 2, 10 and 3, 11 - use Cb and Cr to calculate RGB and place in
// pixel matrix in 2, 18 and 3 and 19
// Quadrant 2
// From Cb -> 5
// From Cr -> 5
// From Y1 -> 2, 10 and 3, 11 - use Cb and Cr to calculate RGB and place in
// pixel matrix in 10, 26 and 11 and 27
// Quadrant 3
// From Cb -> 33
// From Cr -> 33
// From Y2 -> 2, 10 and 3, 11 - use Cb and Cr to calculate RGB and place in
// pixel matrix in 130, 146 and 131 and 147
// Quadrant 4
// From Cb -> 37
// From Cr -> 37
// From Y3 -> 2, 10 and 3, 11 - use Cb and Cr to calculate RGB and place in
// pixel matrix in 138, 154 and 139 and 155
// We need third and fourth loop to complete first two lines of the luma
// blocks. At this time we
// have written 64 pixels to the pixel matrix.
// These four loops have to be repeated 4 more times (4 * 64 = 256) to fill
// complete pixel matrix.
// Remark the offsets to use in the pixel matrix have to take into account
// that an GroupOfBlocks contains multiple pixel matrices.
// So to calculate the real index we have to take that also into account
// (blockCount)
private uint peekStreamData(ByteBuffer stream, int count)
{
uint data = new uint(0);
uint stream_field = streamField;
int stream_field_bit_index = streamFieldBitIndex;
while(count > (32 - stream_field_bit_index) && streamIndex < (imageStream.capacity() >> 2))
{
data = (data.shiftLeft(32 - stream_field_bit_index)).or(stream_field.shiftRight(stream_field_bit_index));
count -= 32 - stream_field_bit_index;
stream_field = new uint(stream, streamIndex * 4);
stream_field_bit_index = 0;
}
if(count > 0)
data = data.shiftLeft(count).or(stream_field.shiftRight((32 - count)));
return data;
}
private void processStream()
{
boolean blockY0HasAcComponents = false;
boolean blockY1HasAcComponents = false;
boolean blockY2HasAcComponents = false;
boolean blockY3HasAcComponents = false;
boolean blockCbHasAcComponents = false;
boolean blockCrHasAcComponents = false;
// Set streamFieldBitIndex to 32 to make sure that the first call to
// ReadStreamData
// actually consumes data from the stream
streamFieldBitIndex = 32;
streamField = new uint(0);
streamIndex = 0;
sliceIndex = 0;
pictureComplete = false;
while(!pictureComplete && streamIndex < (imageStream.capacity() >> 2))
{
readHeader();
if(!pictureComplete)
{
for(int count = 0; count < blockCount; count++)
{
uint macroBlockEmpty = readStreamData(1);
if(macroBlockEmpty.intValue() == (0))
{
uint acCoefficients = readStreamData(8);
blockY0HasAcComponents = acCoefficients.shiftRight(0).and(1).intValue() == 1;
blockY1HasAcComponents = acCoefficients.shiftRight(1).and(1).intValue() == 1;
blockY2HasAcComponents = acCoefficients.shiftRight(2).and(1).intValue() == 1;
blockY3HasAcComponents = acCoefficients.shiftRight(3).and(1).intValue() == 1;
blockCbHasAcComponents = acCoefficients.shiftRight(4).and(1).intValue() == 1;
blockCrHasAcComponents = acCoefficients.shiftRight(5).and(1).intValue() == 1;
if(acCoefficients.shiftRight(6).and(1).intValue() == 1)
{
uint quantizer_mode = readStreamData(2);
quantizerMode = (int) ((quantizer_mode.intValue() < 2) ? quantizer_mode.flipBits()
: quantizer_mode.intValue());
}
getBlockBytes(blockY0HasAcComponents);
inverseTransform(count, 0);
getBlockBytes(blockY1HasAcComponents);
inverseTransform(count, 1);
getBlockBytes(blockY2HasAcComponents);
inverseTransform(count, 2);
getBlockBytes(blockY3HasAcComponents);
inverseTransform(count, 3);
getBlockBytes(blockCbHasAcComponents);
inverseTransform(count, 4);
getBlockBytes(blockCrHasAcComponents);
inverseTransform(count, 5);
}
}
composeImageSlice();
}
}
}
private void readHeader()
{
alignStreamData();
uint code = readStreamData(22);
uint startCode = new uint(code.and(~0x1F));
if(startCode.intValue() == 32)
{
if(((code.and(0x1F).intValue()) == 0x1F))
{
pictureComplete = true;
} else
{
if(sliceIndex++ == 0)
{
pictureFormat = (int) readStreamData(2).intValue();
resolution = (int) readStreamData(3).intValue();
pictureType = (int) readStreamData(3).intValue();
quantizerMode = (int) readStreamData(5).intValue();
frameIndex = (int) readStreamData(32).intValue();
switch(pictureFormat)
{
case CIF:
width = CIF_WIDTH << resolution - 1;
height = CIG_HEIGHT << resolution - 1;
break;
case QVGA:
width = VGA_WIDTH << resolution - 1;
height = VGA_HEIGHT << resolution - 1;
break;
}
// We assume two bytes per pixel (RGB 565)
pixelRowSize = width << 1;
sliceCount = height >> 4;
blockCount = width >> 4;
if(imageSlice == null)
{
imageSlice = new ImageSlice(blockCount);
pixelData = new uint[width * height];
javaPixelData = new int[pixelData.length];
} else
{
if(imageSlice.MacroBlocks.length != blockCount)
{
imageSlice = new ImageSlice(blockCount);
pixelData = new uint[width * height];
javaPixelData = new int[pixelData.length];
}
}
} else
{
quantizerMode = (int) readStreamData(5).intValue();
}
}
}
}
private uint readStreamData(int count)
{
uint data = new uint(0);
while(count > (32 - streamFieldBitIndex))
{
data = (data.shiftLeft((int) (32 - streamFieldBitIndex)).or(streamField.shiftRight(streamFieldBitIndex)));
count -= 32 - streamFieldBitIndex;
streamField = new uint(imageStream, streamIndex * 4);
streamFieldBitIndex = 0;
streamIndex++;
}
if(count > 0)
{
data = data.shiftLeft(count).or(streamField.shiftRight(32 - count));
streamField.shiftLeftEquals(count);
streamFieldBitIndex += count;
}
return data;
}
private static int saturate5(int x)
{
if(x < 0)
return 0;
x >>= 11;
return (x > 0x1F) ? 0x1F : x;
}
private static int saturate6(int x)
{
if(x < 0)
return 0;
x >>= 10;
return x > 0x3F ? 0x3F : x;
}
}
@@ -0,0 +1,46 @@
package com.codeminders.ardrone.video;
// Copyright 2007-2011, PARROT SA, all rights reserved.
// DISCLAIMER
// The APIs is provided by PARROT and contributors "AS IS" and any express or
// implied warranties, including, but not limited to, the implied warranties of
// merchantability
// and fitness for a particular purpose are disclaimed. In no event shall PARROT
// and contributors be liable for any direct, indirect, incidental, special,
// exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or business
// interruption) however
// caused and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of the use
// of this
// software, even if advised of the possibility of such damage.
// Author : Daniel Schmidt
// Publishing date : 2010-01-06
// based on work by : Wilke Jansoone
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions, the disclaimer and the original author of the source
// code.
// - Neither the name of the PixVillage Team, nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
class ImageSlice
{
MacroBlock[] MacroBlocks;
ImageSlice(int macroBlockCount)
{
MacroBlocks = new MacroBlock[macroBlockCount];
for(int index = 0; index < macroBlockCount; index++)
MacroBlocks[index] = new MacroBlock();
}
}
@@ -0,0 +1,46 @@
package com.codeminders.ardrone.video;
// Copyright 2007-2011, PARROT SA, all rights reserved.
// DISCLAIMER
// The APIs is provided by PARROT and contributors "AS IS" and any express or
// implied warranties, including, but not limited to, the implied warranties of
// merchantability
// and fitness for a particular purpose are disclaimed. In no event shall PARROT
// and contributors be liable for any direct, indirect, incidental, special,
// exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or business
// interruption) however
// caused and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of the use
// of this
// software, even if advised of the possibility of such damage.
// Author : Daniel Schmidt
// Publishing date : 2010-01-06
// based on work by : Wilke Jansoone
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions, the disclaimer and the original author of the source
// code.
// - Neither the name of the PixVillage Team, nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
class MacroBlock
{
short[][] DataBlocks;
MacroBlock()
{
DataBlocks = new short[6][];
for(int index = 0; index < 6; index++)
DataBlocks[index] = new short[64];
}
}
@@ -0,0 +1,158 @@
package com.codeminders.ardrone.video;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.nio.ByteBuffer;
// Copyright 2007-2011, PARROT SA, all rights reserved.
// DISCLAIMER
// The APIs is provided by PARROT and contributors "AS IS" and any express or
// implied warranties, including, but not limited to, the implied warranties of
// merchantability
// and fitness for a particular purpose are disclaimed. In no event shall PARROT
// and contributors be liable for any direct, indirect, incidental, special,
// exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or business
// interruption) however
// caused and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of the use
// of this
// software, even if advised of the possibility of such damage.
// Author : Daniel Schmidt
// Publishing date : 2010-01-06
// based on work by : Wilke Jansoone
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions, the disclaimer and the original author of the source
// code.
// - Neither the name of the PixVillage Team, nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission.
public class uint
{
private int base2;
public uint(byte[] bp, int start)
{
try
{
byte[] b = new byte[4];
b[0] = bp[start + 3];
b[1] = bp[start + 2];
b[2] = bp[start + 1];
b[3] = bp[start + 0];
ByteArrayInputStream bas = new ByteArrayInputStream(b);
DataInputStream din = new DataInputStream(bas);
this.base2 = din.readInt();
} catch(Exception e)
{
throw new RuntimeException("error creating uint", e);
}
}
public uint(ByteBuffer bp, int start)
{
try
{
ByteBuffer bb = ByteBuffer.allocate(4);
bb.put(bp.array()[start + 3]);
bb.put(bp.array()[start + 2]);
bb.put(bp.array()[start + 1]);
bb.put(bp.array()[start + 0]);
// bb.put(bp.get(start + 3));
// bb.put(bp.get(start + 2));
// bb.put(bp.get(start + 1));
// bb.put(bp.get(start ));
bb.flip();
this.base2 = bb.getInt();
}
catch(Exception e)
{
throw new RuntimeException("error creating uint", e);
}
}
public uint(int base)
{
this.base2 = base;
}
public uint(uint that)
{
this.base2 = that.base2;
}
public uint and(int andval)
{
int retval = base2 & andval;
return new uint(retval);
}
public int flipBits()
{
int base = ~base2;
return base;
}
public int intValue()
{
return base2;
}
public uint or(uint orval)
{
int retval = base2 | orval.base2;
return new uint(retval);
}
public uint shiftLeft(int i)
{
int base = base2;
base <<= i;
return new uint(base);
}
public void shiftLeftEquals(int i)
{
int base = base2;
base <<= i;
base2 = base;
}
public uint shiftRight(int i)
{
int base = base2;
base = base >>> i;
return new uint(base);
}
public void shiftRightEquals(int i)
{
int base = base2;
base >>>= i;
base2 = base;
}
public short times(short i)
{
return (short) (intValue() * i);
}
public String toString()
{
return Integer.toString(base2, 2);
}
}
Arquivo binário não exibido.
@@ -0,0 +1 @@
2c363d983267d2440d50ea6d3fd0af1ee581f95d
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.codeminders</groupId>
<artifactId>hidapi</artifactId>
<version>1.0</version>
<url>http://code.google.com/p/javahidapi/</url>
<description>JNI wrapper around C/C++ HIDAPI library providing simple java API to work with devices such as USB gamepads, joysticks, keyboards</description>
<licenses>
<license>
<name>BSD License</name>
<url>http://www.opensource.org/licenses/bsd-license.php</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<scm>
<connection>scm:hg:http://code.google.com/p/javahidapi/</connection>
</scm>
</scm>
</project>
@@ -0,0 +1 @@
b13251b02ad7d824472950e02d05746250a55685
+18
Ver Arquivo
@@ -0,0 +1,18 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.codeminders</groupId>
<artifactId>javadrone</artifactId>
<version>${currentVersion}</version>
<name>javadrone</name>
<packaging>pom</packaging>
<description>Java API and demo programs to control Parrot's AR.Drone</description>
<modules>
<module>javadrone-api</module>
<module>controltower</module>
</modules>
<properties>
<currentVersion>1.2</currentVersion>
</properties>
</project>
Arquivo executável
+61
Ver Arquivo
@@ -0,0 +1,61 @@
#!/usr/bin/env python
import sys,os
from subprocess import Popen,PIPE,call
import re,string
INTF="wlan0"
def runCmd(cmd):
retcode = call(string.join(cmd, " "), shell=True)
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
sys.exit(1)
elif retcode!=0:
print >>sys.stderr, "Child returned", retcode
sys.exit(1)
if os.getuid()!=0:
print >>sys.stderr, "Not enough privilidges"
sys.exit(1)
print "Detecting AR Drone"
runCmd(["/sbin/ifconfig", INTF ,"up"])
scanres = Popen(["/sbin/iwlist", INTF, "scan"], stdout=PIPE).communicate()[0]
SSID=None
cells = re.split(r'\s+Cell [0-9]+',scanres)
for c in cells:
m = re.search(r'\s+ESSID\:"(ardrone_[0-9]+)',c)
if m:
SSID=m.group(1)
m = re.search(r'\s+Channel\:([0-9]+)',c)
if not m:
print >>sys.stderr, "Could not detect channel!"
sys.exit(1)
CHANNEL = m.group(1)
break
if SSID:
print "Found Ar.Drone with SSID %s on channel %s" % (SSID,CHANNEL)
else:
print >>sys.stderr, "Ar.Drone not found"
sys.exit(1)
print "Configuring WiFi interface"
runCmd(["/sbin/ifconfig", INTF ,"up"])
runCmd(["/sbin/iwconfig", INTF ,"mode","ad-hoc"])
runCmd(["/sbin/iwconfig", INTF ,"channel",str(CHANNEL)])
runCmd(["/sbin/iwconfig", INTF ,"Bit","54Mb/s"])
runCmd(["/sbin/iwconfig", INTF ,"essid",SSID])
print "Connecting to Ar.Drone"
runCmd(["/sbin/dhclient", INTF])
runCmd(["/sbin/route", "delete", "default", "gw", "192.168.1.1"])
print "Checking connectivity"
runCmd(["/bin/ping", "-c3", "192.168.1.1"])
print "Ar.Drone is ready with IP 192.168.1.1"