Big Blimpin’

Jaylen VanOrden, Peter Dwersteg, Michael Falcone

CSE 466 Final Project

Introduction:

Large scale blimps and other non-rigid airships saw extensive use in both World War I and II, though in modern times they are most commonly used for advertising. Smaller remote controlled blimps have become increasingly popular in recent years for a variety of purposes. Our project, named “Big Blimpin’” allows for remote control of a blimp with a visually appealing graphical user interface (GUI). Users can individually control speed and direction of the three fans that move the blimp; two side fans control turning and forward and backward movement and one downward facing fan moves the blimp up or down depending on direction. The user can also activate “Autonomous Altitude Control Mode” (AACM), essentially a cruise control for the blimp’s altitude, which is measured through a downward facing infrared (IR) light emitting diode (LED) and detector.

Related work:

        Significant work has already been done in the field of radio-controlled blimps. Blimps have been used for academic research purposes, exist in the consumer realm at a variety of levels, and even find use in business, government, and defense applications.

        In the academic community, much of the usage of blimps comes from disciplines outside of computer science. For example, the UW Atmospheric Sciences department uses blimps for weather research (http://www.washington.edu/news/archive/id/58446). However, because there are several applications that blimps may be used for in the future, there is ongoing academic research into areas of improving blimp design such as more efficient propulsion and more effective safety controls.

        In the consumer market, there are a number of different levels of sophistication available at corresponding price points. These range from simple models starting under 100 dollars to significantly larger, more complicated, and more expensive models catering to the extreme hobbyist. In this market, they are mainly used for leisure, and serve little to no practical or scientific purpose.

Most of the modern usage of radio-controlled blimps is in the area of business, government, and defense applications. Here, blimps excel in that they can provide an extremely stable yet manoeuvrable aerial platform for a variety of purposes. Of particular interest and potential are surveillance and lifting. Blimps are very suited to covert surveillance as they are compact and extremely quiet (allowing them to avoid detection significantly better than an airplane could), and their stability and maneuverability would allow clear and precise pictures to be remotely captured. In the realm of heavy lifting, their mechanical simplicity, massive payload capacity (if you want to lift more, just make the bladder larger), and comparative fuel economy with other large transport methods make them a valid option for the future.

At the UW CSE department, blimps are mainly used for educational and project purposes. For example, they are created by students in the embedded systems course to demonstrate understanding of microcontroller programming concepts. Another example is the blimp created by the Engineering Emerging Leaders group as a project, and to get young students excited about college and the sciences (http://www.washington.edu/news /archive/

id/58446).

System Design & Implementation:

         HW Description:

The blimp itself is a PCB custom-designed for the project suspended from a 52 inch by 24 inch helium-filled air bladder (http://www.rctoys.com/rc-products/MACH-ZENV -SILVER

.html).

The hardware required for maneuvering the blimp is all affixed to the PCB. Mounted on the PCB are three motors with propellers attached. Two are mounted on a single horizontal boom fixed to the PCB with zip ties. The propellers on these two motors face to the rear and are used for forward and backward propulsion. The third motor is attached to a boom that sits perpendicular to the surface of the PCB, and its propeller faces downwards to apply upward and downward thrust.

Directly soldered to the PCB are the chips, peripherals, and microcontrollers used to control the blimp. At its core is the Texas Instruments MSP430F5510 microcontroller (5510). Attached to the 5510 are several subsystems. These are IR sensing, motor control, E-Field sensing, wireless communication, and the compass.

The IR sensing subsystem is made up of five separate IR emitter LEDs (the MMBTA13) mounted facing forwards, backwards, to either side, and downwards. These LEDs are individually triggered using a 3-8 demultiplexer (the 74HC238). The IR radiation is then measured by a photodiode mounted on the underside of the PCB.

The motor control subsystem is a LV8405 H-bridge IC that takes control input from the 5510.

E-Field sensing is done using two optional electrical field sensors attached to an op-amp which outputs the result to the 5510.

The wireless communication subsystem consists of an EZ430-RF2500 chip to send the data wirelessly, which communicates with the 5510 using a UART system. At the other end of the wireless connection is another EZ430-RF2500 that communicates with a PC using a similar wired UART system.

The compass is an HMC5883L IC mounted on the periphery of the PCB that outputs to the 5510 (see figures 5  - 10  in the appendix for a full hardware block diagram).

         Firmware Description:

        The blimp firmware on the 5510 keeps the blimp idle by default and ready to receive messages from the RF2500. The 5510 constantly checks for serial data and immediately decodes the bytes. These bytes may be settings for fans, a command to kill any currently running processes (including fans, sensors, etc.), or a command to begin “Autonomous Altitude Control Mode” (AACM).

GUI Description:

        The graphical user interface (GUI) designed to work with Big Blimpin’ is a very straightforward set of buttons and keyboard controls. Users can choose to use forward/reverse/turn right/turn left commands or can choose to control each fan separately.  Both methods are usable from a USB 10-key pad, which allows easier control from laptops, etc. based on the keyboard shortcuts listed on each button.  The currently commanded fan levels are displayed on screen, along with an altitude gauge that functions when the blimp is in auto-altitude mode.  The GUI interfaces with the blimp using a serial communication library in Java.

Figure 1 :  The computer-side control GUI

Figure 2:  Basic overview of the software design and communication for blimp control.

Wired UART communication:
        The UART for the blimp system connects a PC running our Java-based GUI to the 5510 on the blimp board through two RF2500 chips that communicate wirelessly. We programmed the RF2500s to pair automatically with each other upon powering up and to simply pass bytes between each other to their respective serial lines for the blimp/PC.

         Command Encoding:

        All commands transmitted to the blimp are encoded in a single byte of data (the smallest amount of data possible to send) to make communication and command execution as quick as possible. The purpose of the command, whether it’s meant to control motors or sensors, is encoded in the first bit, with the remaining bits containing more specific information. For motor control the next seven bits contain which motor to control, the direction the motor should spin (forward or backward), and the velocity to set the motor to spin at (with 7 different speed settings). For sensor read commands, the next several bits determine what category of sensor is to be read (compass, E-Field, IR, or battery). If, as in the case of IR, there are multiple sensors in that category on the blimp board, the next bits are used to indicate which sensor value is to be returned.

Figure 3 :  Byte encoding system for motor and sensor commands.  Note that many bit patterns are available for future commands.

        Once the command byte has been received by the 5510 on the blimp board, there is a suite of functions that are called that extract the information it contains. These are used to determine whether the command is for motor control or sensor reading, and then get the other information contained.

         Motor Control:

        If a motor control command is received, the motor selection bits are used to determine which motor is to be controlled, and the appropriate global variables are set. The direction bit is used to set which direction the propeller will spin. Finally, the value of the velocity bits is used to select from a set of preset PWM frequencies to change the speed at which the propeller will spin. This PWM signal is then controlled by an interrupt service routine (ISR) which outputs to the motor control IC. Alternatively, all the motors can be controlled simultaneously with a special value of the motor selection bits.

         Altitude Control:

        Entering AACM means the blimp immediately takes an IR reading by requesting 32 sequential readings from the IR sensor, flashing the downward facing LED on every other reading. This initial reading is used to calibrate the altitude that the blimp will attempt to maintain. The 5510 then begins constantly taking more IR readings. If a reading indicates that the blimp has passed below the previously calibrated threshold, then the bottom fan is pulsed downward for a short period of time until the IR sensor indicates that the blimp has risen above the threshold. The blimp’s altitude can be re-calibrated at any time by sending another command from the PC GUI to enter AACM. While in this mode, the blimp is also reporting every IR reading taken back to the PC via the RF2500/RF2500 wireless and wired UARTs. The blimp will remain in AACM until either a “kill all” command is received from the PC or more specifically when a command is received to exit AACM.

Extras:

        When we were first debugging the blimp board, it was essential that we have a robust serial connection to the MSP430F5510, rather than the (at the time) somewhat spotty radio transmitters. Unfortunately the serial pins on the debugger weren’t wired to connect to the 5510 by default, so in order to facilitate serial communication between our computer and the blimp we soldered together a small dongle that sits between the debugger and the blimp board and routes the serial pins to some headers that we soldered onto the blimp board on the 5510’s serial ports. This device proved extremely useful throughout the development process, even once we had the radios working properly.

We also added two LEDs on the back of the blimp that indicate when each of the two side fans are running in reverse. We accomplished this having our radio MSP430 on the blimp peek at each packet it receives; if the packet is a motor control command, then the MSP430 changes the LED outputs.

Results:

          Our blimp system was a success on many fronts, but also fell short in several categories.

We devised our own encoding system to fit every type of command we would potentially want to send to the blimp into a single byte. In order to make the encoding conventions universal throughout our code, we wrote a header file that used #defines to define certain values that we use repeatedly and want to interpret as specific motor or sensor commands. In addition to these definitions we also wrote several handy macros that serve to mask the proper bits to pull the relevant data out of any message byte. This encoding was developed very early on in the project, but required very few additions and edits throughout the course of creating the blimp system.

Motor control was another success for us, as we developed our own PWM scheme to control the three fans. By design the two side fans were wired directly to their own individual timers that would control the speed of the fans. This left us to devise our own scheme for the bottom fan, and we ended up using our PWM scheme for all three fans for the sake of simplicity. To do this we used a timer ISR running at close to 1 Khz to move a basic state machine through 7 sequential states (numbered 1 through 7). To control fan speed we simply compare the current speed of each fan to the current ISR state, if the speed is less than or equal to the current state, we run the fan until the next interrupt, when the same comparison is made, otherwise the fan is turned off. This allows us to have seven different speeds on each fan in each direction, even though we only output high or low to the fan motor.

        Autonomous Altitude Control Mode (AACM) was relatively successful in our implementation of the blimp. We had some initial issues with the IR sensor, but were able to ultimately gather relatively useful data at a quick enough pace to keep the blimp from hitting the floor. While developing AACM we came up with the idea to “calibrate” the blimp’s altitude threshold every time the blimp entered AACM. This idea ended up working out much better than coming up with an arbitrary threshold, as the values returned by the IR sensor would generally be consistent over short periods of time but very inconsistent over longer periods. Being able to recalibrate the blimp’s threshold--without reprogramming a hard-coded variable on the 5510--ending up making AACM much more viable and effective in the long run.

Unfortunately, we ran into several problems that we weren’t able to overcome within our given time frame.

Our ability to actually pilot the blimp was not quite as accurate as we had hoped it would become. The blimp would often fly in circles when we would attempt to go forward. This could have been caused by many different real world issues such as air currents in the lab, difference in speeds between the two side fans, or crooked mounting of the blimp board on the envelope. Fins were mounted on the rear of the blimp in an attempt to help this issue, but since they were a last minute addition they were made of flimsy paper and didn’t have much of an effect. If we had more time to find some thicker paper it’s possible that the fins would have helped stabilize the blimp more than the paper ones did.

Our Automated Altitude Control Mode, though generally a success, could have been more robust. The blimp would often “rubber band” when the IR detector detected ground nearby, as the bottom fan would turn on high and give the blimp a significant amount of upward momentum before shutting off as the blimp passed high above the threshold. The blimp would hit the top of its climb and slowly fall towards the ground, gaining momentum all the while. This momentum would often cause the blimp to hit the ground even after the fan had turned on to propel it upwards, and the whole cycle could then repeat. This was only much of a problem with height thresholds of less than six inches, and generally up to about four or five feet the blimp would perform much better in AACM. This could have been solved by using a more sophisticated control algorithm, such as PID, rather than our “bang bang” algorithm.

Finally, we had some trouble using the serial-wireless-serial system.  If we sent bytes too close together in time, we lost the second one.  This is most likely due to concurrency issues on the sending RF2500.  To work around this problem, we use a 750 ms hard-coded delay between bytes output from the computer.  This limitation is imposed at the serial-class layer of the GUI control code.

Future work:

        With more work, Big Blimpin’ could become a much more advanced and capable system that it is in its current state; the majority of the sensors and peripherals already available on the blimp PCB are unused. For example, further work could be done to implement the reading of the remaining four infrared LED’s and doing further collision avoidance work with the data gathered.  Additionally, the compass remains unused, which could be used to direct the blimp to travel in a specific direction using the GUI, or be used to simply gather directional data. A more robust serial-to-wireless handler would be developed to allow packets to be sent in rapid succession.  Finally, the blimp has an electromagnetic field sensor, which could be used in some sort of function. These individual functionalities could then be combined into higher level behavior for the blimp, such as exploring three-dimensional spaces and avoiding obstacles.

        We have several suggestions for the next generation of the blimp hardware. The first is to use higher quality infrared sensors. In the case of our board, they could only detect the ground approximately 3-4 inches away from the tip of the ventral propeller. This was an issue because if the blimp had any momentum when it reached this altitude, then it was probable that even if the propeller turned on at the correct moment with maximum speed, the propeller boom would still impact the ground before the velocity was reversed. With higher quality and more sensitive infrared sensors, this obstacle detection distance could be increased, and more accurate and refined collision detection and avoidance behavior could be implemented.

        Another suggestion would be to use a more reliable and robust programming environment than Code Composer Studio. There were several instances when our work was stalled for a significant amount of time due to issues with the program. For example, there were difficulties in detecting the microcontroller to be programmed despite the fact that one was plugged in. Additionally, there were several times when Code Composer froze then refused to re-open the workspace we were using, forcing us to restart the computer (not a quick proposition on the computers in Lab 003). This project would have gone substantially smoother if we had a more robust coding environment.        Similarly, the virtual com port system failed very often, requiring replugging and troubleshooting during most part of development.  The use of a converter / adapter to allow use of built-in com ports would likely improve the serial connection stability and may also affect the stability of the programming environment.


Appendix A - Additional Figures

Figure 4 :  IR read values when blimp was hovering at a calibrated point and after blimp was commanded to hold at a higher altitude.  Approximately 10 seconds of data for each section.

Figure 5 :  Overall board design diagram, courtesy Aaron Parks

Figure 6 :  Voltage regulation and power switch diagram, courtesy Aaron Parks

Figure 7 :  Motor driver diagram, courtesy Aaron Parks

Figure 8:  Infra-red LED diagram, courtesy Aaron Parks

Figure 9:  Infra-red receiver diagram, courtesy Aaron Parks

Figure 10:  E-field sensor diagram, courtesy Aaron Parks


Appendix B - GUI software

ZeppelGUImain.java

// CSE 466 Blimp Project

// 12-14-2011

// Peter Dwersteg

// Michael Falcone

// Jaylen VanOrden

public class ZeppelGUImain {

        

        public static void sop(String t){

                System.out.println(t);

        }

        

        public static void main(String[] args){

                ZeppelGUI mainGUI = new ZeppelGUI();

                

        }

        

        public static void testCodes(){

                sop("All back full should be 255");

                sop("Answer: " + (ZH.M_SND_MOTOR_CMD(ZH.MOTOR_ID_FORWARD, ZH.MOTOR_DIR_REVERSE, ZH.MOTOR_VEL_HIGHEST )));

                

                sop("Bottom->6 should be 201");

                sop("Answer: " + (ZH.M_SND_MOTOR_CMD(ZH.MOTOR_ID_BOTTOM, ZH.MOTOR_DIR_FORWARD, ZH.MOTOR_VEL_HIGHER )));

                

                sop("Bottom->7 should be 233");

                sop("Answer: " + (ZH.M_SND_MOTOR_CMD(ZH.MOTOR_ID_BOTTOM, ZH.MOTOR_DIR_FORWARD, ZH.MOTOR_VEL_HIGHEST )));

                

                sop("All ahead full should be 239");

                sop("Answer: " + (ZH.M_SND_MOTOR_CMD(ZH.MOTOR_ID_FORWARD, ZH.MOTOR_DIR_FORWARD, ZH.MOTOR_VEL_HIGHEST )));

                

                sop("All ahead half should be 79");

                sop("Answer: " + (ZH.M_SND_MOTOR_CMD(ZH.MOTOR_ID_FORWARD, ZH.MOTOR_DIR_FORWARD, ZH.MOTOR_VEL_LOWER )));

                

                sop("All ahead half should be 95");

                sop("Answer: " + (ZH.M_SND_MOTOR_CMD(ZH.MOTOR_ID_FORWARD, ZH.MOTOR_DIR_REVERSE, ZH.MOTOR_VEL_LOWER )));

                

                sop("Right ahead should be 237 ( was left ahead )");

                sop("Answer: " + (ZH.M_SND_MOTOR_CMD(ZH.MOTOR_ID_RIGHT, ZH.MOTOR_DIR_FORWARD, ZH.MOTOR_VEL_HIGHEST )));

                

                sop("Start poll should be 32");

                sop("Answer: " + (ZH.M_SND_SENSOR_RQST(ZH.SENSOR_IR, ZH.SENSOR_IR_START_POLLING)));

                

                sop("Stop poll should be 64");

                sop("Answer: " + (ZH.M_SND_SENSOR_RQST(ZH.SENSOR_IR, ZH.SENSOR_IR_STOP_POLLING)));

                

                sop("Left poll should be 192");

                sop("Answer: " + (ZH.M_SND_SENSOR_RQST(ZH.SENSOR_IR, ZH.SENSOR_IR_LEFT)));

        }

}

ZeppelGUI.java

// CSE 466 Blimp Project

// 12-14-2011

// Peter Dwersteg

// Michael Falcone

// Jaylen VanOrden

import java.awt.BorderLayout;

import java.awt.Color;

import java.awt.Dimension;

import java.awt.FlowLayout;

import java.awt.Font;

import java.awt.GridLayout;

import java.awt.Image;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;

import javax.swing.BorderFactory;

import javax.swing.BoxLayout;

import javax.swing.Icon;

import javax.swing.ImageIcon;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JPanel;

import javax.swing.JProgressBar;

import javax.swing.SwingConstants;

public class ZeppelGUI extends JFrame implements ZeppelinObserver {

        

        private static final boolean DEBUG = false;

        private static final int CONTROL_WIDTH         = 550;

        private static final int CONTROL_HEIGHT = 300;

        private static final String TITLE_STRING = "Advanced control | My Little Pony: Friendship is Zeppelin | Big Blimpin";

        

        private static int WINDOW_WIDTH  = 1000;

        private static int WINDOW_HEIGHT = 600;

        

        private volatile int maxAltSeen = 0;

        private volatile int minAltSeen = 0;

        

        private KeyboardListener keyListener;

        private OmniButtonListener buttonListen;

        private Zeppelin myZeppelin;

        

        // Thanks to http://web.forret.com for a color palette

        private Color leftFanColor = new Color(0x90, 0xEE, 0x90);

        private Color verticalFanColor = new Color(0x87, 0xCE, 0xEB);

        private Color rightFanColor = new Color(0xF0, 0xE6, 0x8C);

        

        private JPanel zeppPanel;

        private JPanel mainPanel;

        private JPanel blimpStatus;

        private JPanel blimpControl;

        private JPanel controlCenter;

        private JPanel mainControl;

        private JPanel altitudeControl;

        private JPanel altitudeGauge;

        private JPanel autoManual;

        private JPanel sentPanel;

        private JButton killAll;

        

        private JButton forwardCtrl;

        private JButton backCtrl;

        private JButton turnRCtrl;

        private JButton turnLCtrl;        

        

        private JButton rightUpCtrl;

        private JButton rightOffCtrl;

        private JButton rightDownCtrl;

        

        private JButton leftUpCtrl;

        private JButton leftOffCtrl;

        private JButton leftDownCtrl;

        

        private JButton verticalUpCtrl;

        private JButton verticalOffCtrl;

        private JButton verticalDownCtrl;

        

        private JButton autoHeight;

        private JButton manualHeight;

        

        private JProgressBar altitudeBar;

        

        private ImageIcon myLittleZeppelin;

        private ImageIcon myLittlePony;

        

        private JLabel zeppelin;

        

        private JLabel rightFanTitle;

        private JLabel leftFanTitle;

        private JLabel verticalFanTitle;

        

        private JLabel rightFan;

        private JLabel leftFan;

        private JLabel verticalFan;

        

        private JLabel altitudeHeader;

        

        private JLabel nullHeader;

        private JLabel leftHeader;

        private JLabel verticalHeader;

        private JLabel rightHeader;

        private JLabel increaseHeader;

        private JLabel zeroHeader;

        private JLabel decreaseHeader;

        private JLabel leftHeader2;

        private JLabel verticalHeader2;

        private JLabel rightHeader2;

        private JLabel increaseHeader2;

        private JLabel zeroHeader2;

        private JLabel decreaseHeader2;

        

        private JLabel sentData;

        

        public ZeppelGUI(){

                super();

                

                buttonListen = new OmniButtonListener();

                myZeppelin = new Zeppelin();

                myZeppelin.setZeppelinObserver(this);

                keyListener = new KeyboardListener();

                

                myLittlePony = new ImageIcon("/pics/MLP_icon.png");

                myLittleZeppelin = new ImageIcon(getClass().getResource("/pics/MLZ.png"));

                

                if(myLittlePony == null || myLittleZeppelin == null){

                        System.out.println("Problem getting icons");

                }

                

                init();

        }

        

        private void init(){

                

                // outer Box layout

                mainPanel = new JPanel();

                mainPanel.setLayout(new BoxLayout(mainPanel,BoxLayout.Y_AXIS));

                mainPanel.addKeyListener(keyListener);

                this.setLayout(new BorderLayout());

                this.add(mainPanel, BorderLayout.CENTER);

                

                // add key listener

                this.setFocusable(true);

                this.addKeyListener(keyListener);

                

                // Top box - simple image

                zeppPanel = new JPanel(new FlowLayout());

                zeppPanel.addKeyListener(keyListener);

                

                                if(DEBUG) System.out.println("The zeppelin: " + myLittleZeppelin.toString());

                                zeppelin = new JLabel(myLittleZeppelin);

                                zeppelin.addKeyListener(keyListener);

                        zeppPanel.add(zeppelin);

                mainPanel.add(zeppPanel);

                

                

                // Second box - blimp status

                blimpStatus = new JPanel(new GridLayout(2,3));

                blimpStatus.addKeyListener(keyListener);

                

                        // North - JLabel for blimp picture

                        //blimpPic = new JLabel("BLIMP", fanIcon, JLabel.CENTER);

                        //blimpPic.addKeyListener(keyListener);

                        //blimpStatus.add(blimpPic, BorderLayout.NORTH);

                        // 0,0 - JLabel for left fan

                        leftFanTitle = new JLabel("Left Fan",JLabel.CENTER);

                        leftFanTitle.setFont(new Font("Times New Roman",Font.BOLD, 24));

                        leftFanTitle.addKeyListener(keyListener);

                        blimpStatus.add(leftFanTitle);

                

                        // 0,1 - JLabel for bottom fan

                        verticalFanTitle = new JLabel("Vertical Fan", JLabel.CENTER);

                        verticalFanTitle.setFont(new Font("Times New Roman",Font.BOLD, 24));

                        verticalFanTitle.addKeyListener(keyListener);

                        blimpStatus.add(verticalFanTitle);

                

                        // 0,2 - JLabel for right fan

                        rightFanTitle = new JLabel("Right Fan", JLabel.CENTER);

                        rightFanTitle.setFont(new Font("Times New Roman",Font.BOLD, 24));

                        rightFanTitle.addKeyListener(keyListener);

                        blimpStatus.add(rightFanTitle);

                

                        // 1,0 - JLabel for left fan velocity info

                        leftFan = new JLabel("0", JLabel.CENTER);

                        leftFan.setFont(new Font("Times New Roman",Font.PLAIN, 36));

                        leftFan.addKeyListener(keyListener);

                        blimpStatus.add(leftFan);

                        

                        // 1,1 - JLabel for bottom fan velocity info

                        verticalFan = new JLabel("0", JLabel.CENTER);

                        verticalFan.setFont(new Font("Times New Roman",Font.PLAIN, 36));

                        verticalFan.addKeyListener(keyListener);

                        blimpStatus.add(verticalFan);

                        

                        // 1,2 - JLabel for right fan velocity info

                        rightFan = new JLabel("0", JLabel.CENTER);

                        rightFan.setFont(new Font("Times New Roman",Font.PLAIN, 36));

                        rightFan.addKeyListener(keyListener);

                        blimpStatus.add(rightFan);

                        

                        // Colors!

                        rightFanTitle.setBackground(rightFanColor);

                        leftFanTitle.setBackground(leftFanColor);

                        verticalFanTitle.setBackground(verticalFanColor);

                        rightFan.setBackground(rightFanColor);

                        leftFan.setBackground(leftFanColor);

                        verticalFan.setBackground(verticalFanColor);

                        

                        rightFanTitle.setOpaque(true);

                        leftFanTitle.setOpaque(true);

                        verticalFanTitle.setOpaque(true);

                        rightFan.setOpaque(true);

                        leftFan.setOpaque(true);

                        verticalFan.setOpaque(true);

                        blimpStatus.validate();

                        

                mainPanel.add(blimpStatus);

                

                // Third box - blimp control

                blimpControl = new JPanel(new BorderLayout());//new GridLayout(1,2));

                blimpControl.addKeyListener(keyListener);

                        

                        // Left box - control center

                        controlCenter = new JPanel(new BorderLayout());

                        controlCenter.addKeyListener(keyListener);

                        controlCenter.setBackground(Color.pink);

                        

                                // North - JButton for forward control

                                forwardCtrl = new JButton("L/R increase [up]");

                                forwardCtrl.addKeyListener(keyListener);

                                forwardCtrl.addActionListener(buttonListen);

                                controlCenter.add(forwardCtrl, BorderLayout.NORTH);

                        

                                // East - JButton for forward control

                                turnRCtrl = new JButton("Turn[Right]");

                                turnRCtrl.addKeyListener(keyListener);

                                turnRCtrl.addActionListener(buttonListen);

                                controlCenter.add(turnRCtrl, BorderLayout.EAST);

                                

                                // South - JButton for backward control

                                backCtrl = new JButton("L/R decrease [down]");

                                backCtrl.addKeyListener(keyListener);

                                backCtrl.addActionListener(buttonListen);

                                controlCenter.add(backCtrl, BorderLayout.SOUTH);

                        

                                // West - JButton for forward control

                                turnLCtrl = new JButton("Turn[Left]");

                                turnLCtrl.addKeyListener(keyListener);

                                turnLCtrl.addActionListener(buttonListen);

                                controlCenter.add(turnLCtrl, BorderLayout.WEST);

                                

                                // Center - grid for up/down control buttons

                                mainControl = new JPanel(new GridLayout(5,5));

                                mainControl.addKeyListener(keyListener);

                                //mainControl.setPreferredSize(new Dimension(CONTROL_WIDTH, CONTROL_HEIGHT));//550,300));

                        

                                        // 0,0 - JLabel for a placeholder

                                        nullHeader = new JLabel(" ", JLabel.CENTER);

                                        nullHeader.addKeyListener(keyListener);

                                        mainControl.add(nullHeader);

                                

                                        // 0,1 - JLabel for left control

                                        leftHeader = new JLabel("Left", JLabel.CENTER);

                                        leftHeader.addKeyListener(keyListener);

                                        mainControl.add(leftHeader);

                                

                                        // 0,2 - JLabel for vertical control

                                        verticalHeader = new JLabel("Vertical", JLabel.CENTER);

                                        verticalHeader.addKeyListener(keyListener);

                                        mainControl.add(verticalHeader);

                                        

                                        // 0,3 - JLabel for right control

                                        rightHeader = new JLabel("Right", JLabel.CENTER);

                                        rightHeader.addKeyListener(keyListener);

                                        mainControl.add(rightHeader);

                                        

                                        // 0,4 - JLabel for a placeholder

                                        nullHeader = new JLabel(" ", JLabel.CENTER);

                                        nullHeader.addKeyListener(keyListener);

                                        mainControl.add(nullHeader);

                                        

                                        // 1,0 - JLabel for increase

                                        increaseHeader = new JLabel("Incr.", JLabel.CENTER);

                                        increaseHeader.addKeyListener(keyListener);

                                        mainControl.add(increaseHeader);

                                        

                                        // 1,1 - JButton for left incr. control

                                        leftUpCtrl = new JButton("q|7");

                                        leftUpCtrl.addKeyListener(keyListener);

                                        leftUpCtrl.setBackground(leftFanColor.brighter());

                                        leftUpCtrl.addActionListener(buttonListen);

                                        mainControl.add(leftUpCtrl);

                                

                                        // 1,2 - JButton for bottom incr. control

                                        verticalUpCtrl = new JButton("w|8");

                                        verticalUpCtrl.addKeyListener(keyListener);

                                        verticalUpCtrl.setBackground(verticalFanColor.brighter());

                                        verticalUpCtrl.addActionListener(buttonListen);

                                        mainControl.add(verticalUpCtrl);

                                        

                                        // 1,3 - JButton for right incr. control

                                        rightUpCtrl = new JButton("e|9");

                                        rightUpCtrl.addKeyListener(keyListener);

                                        rightUpCtrl.setBackground(rightFanColor.brighter());

                                        rightUpCtrl.addActionListener(buttonListen);

                                        mainControl.add(rightUpCtrl);

                                        

                                        // 1,4 - JLabel for increase

                                        increaseHeader2 = new JLabel("Incr.", JLabel.CENTER);

                                        increaseHeader2.addKeyListener(keyListener);

                                        mainControl.add(increaseHeader2);

                                        

                                        // 2,0 - JLabel for zero

                                        zeroHeader = new JLabel("Stop", JLabel.CENTER);

                                        zeroHeader.addKeyListener(keyListener);

                                        mainControl.add(zeroHeader);

                                        

                                        // 2,1 - JButton for left shutoff

                                        leftOffCtrl = new JButton("a|4");

                                        leftOffCtrl.setBackground(leftFanColor);

                                        leftOffCtrl.addKeyListener(keyListener);

                                        leftOffCtrl.addActionListener(buttonListen);

                                        mainControl.add(leftOffCtrl);

                                        // 2,2 - JButton for bottom shutoff

                                        verticalOffCtrl = new JButton("s|5");

                                        verticalOffCtrl.addKeyListener(keyListener);

                                        verticalOffCtrl.setBackground(verticalFanColor);

                                        verticalOffCtrl.addActionListener(buttonListen);

                                        mainControl.add(verticalOffCtrl);

                                        

                                        // 2,3 - JButton for right shutoff

                                        rightOffCtrl = new JButton("d|6");

                                        rightOffCtrl.addKeyListener(keyListener);

                                        rightOffCtrl.setBackground(rightFanColor);

                                        rightOffCtrl.addActionListener(buttonListen);

                                        mainControl.add(rightOffCtrl);

                                        

                                        // 2,4 - JLabel for zero

                                        zeroHeader2 = new JLabel("Stop", JLabel.CENTER);

                                        zeroHeader2.addKeyListener(keyListener);

                                        mainControl.add(zeroHeader2);

                                        

                                        // 3,0 - JLabel for decrease

                                        decreaseHeader = new JLabel("Decr.", JLabel.CENTER);

                                        decreaseHeader.addKeyListener(keyListener);

                                        mainControl.add(decreaseHeader);

                                        

                                        // 3,1 - JButton for left decr. control

                                        leftDownCtrl = new JButton("z|1");

                                        leftDownCtrl.setBackground(leftFanColor.darker());

                                        leftDownCtrl.addKeyListener(keyListener);

                                        leftDownCtrl.addActionListener(buttonListen);

                                        mainControl.add(leftDownCtrl);

                                        // 3,2 - JButton for bottom decr. control

                                        verticalDownCtrl = new JButton("x|2");

                                        verticalDownCtrl.addKeyListener(keyListener);

                                        verticalDownCtrl.setBackground(verticalFanColor.darker());

                                        verticalDownCtrl.addActionListener(buttonListen);

                                        mainControl.add(verticalDownCtrl);

                                        

                                        // 3,3 - JButton for right decr. control

                                        rightDownCtrl = new JButton("c|3");

                                        rightDownCtrl.addKeyListener(keyListener);

                                        rightDownCtrl.setBackground(rightFanColor.darker());

                                        rightDownCtrl.addActionListener(buttonListen);

                                        mainControl.add(rightDownCtrl);

                        

                                        // 3,4 - JLabel for decrease

                                        decreaseHeader2 = new JLabel("Decr.", JLabel.CENTER);

                                        decreaseHeader2.addKeyListener(keyListener);

                                        mainControl.add(decreaseHeader2);

                                        

                                        // 4,0 - JLabel for a placeholder

                                        nullHeader = new JLabel(" ", JLabel.CENTER);

                                        nullHeader.addKeyListener(keyListener);

                                        mainControl.add(nullHeader);

                                        

                                        // 4,1 - JLabel for left control

                                        leftHeader2 = new JLabel("Left", JLabel.CENTER);

                                        leftHeader2.addKeyListener(keyListener);

                                        mainControl.add(leftHeader2);

                                

                                        // 4,2 - JLabel for vertical control

                                        verticalHeader2 = new JLabel("Vertical", JLabel.CENTER);

                                        verticalHeader2.addKeyListener(keyListener);

                                        mainControl.add(verticalHeader2);

                                        

                                        // 4,3 - JLabel for right control

                                        rightHeader2 = new JLabel("Right", JLabel.CENTER);

                                        rightHeader2.addKeyListener(keyListener);

                                        mainControl.add(rightHeader2);

                                        

                                        // 4,4 - JLabel for a placeholder

                                        nullHeader = new JLabel(" ", JLabel.CENTER);

                                        nullHeader.addKeyListener(keyListener);

                                        mainControl.add(nullHeader);

                                        

                                controlCenter.add(mainControl, BorderLayout.CENTER);

                        

                        blimpControl.add(controlCenter, BorderLayout.CENTER);

                        

                        // Right box - altitude information and control

                        altitudeControl = new JPanel(new GridLayout(1,2));

                        altitudeControl.addKeyListener(keyListener);

                        altitudeControl.addKeyListener(new KeyboardListener());

                        

                                // Left altitude control - altitude bar

                                altitudeGauge = new JPanel(new BorderLayout());

                                altitudeGauge.addKeyListener(keyListener);

                                

                                        // Top - altitude gauge label

                                        altitudeHeader = new JLabel("Auto-Altitude Gauge", JLabel.CENTER);

                                        altitudeHeader.addKeyListener(keyListener);

                                        

                                        altitudeGauge.add(altitudeHeader, BorderLayout.NORTH);

                                        

                                        // Bottom -  altitude gauge as progress bar

                                        altitudeBar = new JProgressBar(SwingConstants.VERTICAL, 0, 0);

                                        altitudeBar.addKeyListener(keyListener);

                                        altitudeBar.setValue(50);

                                        

                                        altitudeGauge.add(altitudeBar, BorderLayout.CENTER);

                                        

                                altitudeControl.add(altitudeGauge);

                        

                                // Right altitude control - auto vs. manual grid

                                autoManual = new JPanel(new GridLayout(3,1));

                                autoManual.addKeyListener(keyListener);

                                

                                        // Top control - Auto height hold

                                        autoHeight = new JButton("Auto altitude hold");

                                        autoHeight.addKeyListener(keyListener);

                                        autoHeight.addActionListener(buttonListen);

                                        autoManual.add(autoHeight);

                                        

                                        // Middle control - Manual altitude

                                        manualHeight = new JButton("Manual altitude");

                                        manualHeight.addKeyListener(keyListener);

                                        manualHeight.addActionListener(buttonListen);

                                        autoManual.add(manualHeight);

                                

                                        // Bottom control - kill all button

                                        killAll = new JButton("All stop");

                                        killAll.addKeyListener(keyListener);

                                        killAll.addActionListener(buttonListen);

                                        killAll.setBackground(Color.red);

                                        

                                        autoManual.add(killAll);

                                        

                                altitudeControl.add(autoManual);

                                

                        blimpControl.add(altitudeControl, BorderLayout.EAST);

                        

                mainPanel.add(blimpControl);

                        

                // Bottom box - sent command bar

                /*sentPanel = new JPanel(new FlowLayout());

                sentPanel.addKeyListener(keyListener);

                

                        sentData = new JLabel("Sent this now!", JLabel.LEFT);

                        sentData.addKeyListener(keyListener);

                        sentData.setBackground(Color.gray);

                        sentData.setOpaque(true);

                        

                        sentPanel.add(sentData);

                        

                mainPanel.add(sentPanel);*/

                

                // Finish initialization

                this.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);

                this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                this.setResizable(false);

                

                this.setTitle(TITLE_STRING);

                

                this.setIconImage(myLittlePony.getImage());

                

                this.setVisible(true);

                this.toFront();

        }

        

        @Override

        public void updateAltitude(int newAltitude) {

                if(newAltitude > maxAltSeen){

                        maxAltSeen = newAltitude;

                        altitudeBar.setMaximum(maxAltSeen);

                        System.out.println("New max: " + maxAltSeen);

                }

                

                if(newAltitude < minAltSeen){

                        minAltSeen = newAltitude;

                        altitudeBar.setMinimum(minAltSeen);

                        System.out.println("New min: " + minAltSeen);

                }

                

                altitudeBar.setValue(maxAltSeen - newAltitude);

                altitudeGauge.validate();

        }

        

        private void resetState(){

                enableVerticalControl();

        }

        

        private void disableVerticalControl(){

                verticalUpCtrl.setEnabled(false);

                verticalOffCtrl.setEnabled(false);

                verticalDownCtrl.setEnabled(false);

                verticalFanTitle.setEnabled(false);

                verticalFan.setEnabled(false);

        }

        

        private void enableVerticalControl(){

                verticalUpCtrl.setEnabled(true);

                verticalOffCtrl.setEnabled(true);

                verticalDownCtrl.setEnabled(true);

                verticalFanTitle.setEnabled(true);

                verticalFan.setEnabled(true);

        }

        

        public void updateGUI(){

                if(DEBUG) System.out.println("Updating GUI!");

                

                // Update to show the new state of the zeppelin fans!

                rightFan.setText("" + myZeppelin.getLeftFanVel());

                leftFan.setText("" + myZeppelin.getRightFanVel());

                verticalFan.setText("" + myZeppelin.getBottomFanVel());

                

                // Should be updated every time it changes...

                //this.updateAltitude(myZeppelin.getAltitude());

        }

        

        

        private class KeyboardListener implements KeyListener{

                @Override

                public void keyPressed(KeyEvent arg0) {

                        switch(arg0.getKeyCode()){

                                case KeyEvent.VK_LEFT:

                                        if(DEBUG) System.out.println("Left pressed!");

                                        turnLCtrl.doClick();

                                        break;

                                case KeyEvent.VK_RIGHT:

                                        if(DEBUG) System.out.println("Right pressed!");

                                        turnRCtrl.doClick();

                                        break;

                                case KeyEvent.VK_UP:

                                        if(DEBUG) System.out.println("Up pressed!");

                                        forwardCtrl.doClick();

                                        break;

                                case KeyEvent.VK_DOWN:

                                        if(DEBUG) System.out.println("Down pressed!");

                                        backCtrl.doClick();

                                        break;

                                default:

                                        break;

                        }

                }

                @Override

                public void keyReleased(KeyEvent arg0) {

                }

                @Override

                public void keyTyped(KeyEvent arg0) {

                        if(DEBUG) System.out.println("Key typed: " + arg0.getKeyChar());

                        

                        int typed = arg0.getKeyChar();

                        switch(typed){

                                case 'q':

                                case 'Q':

                                case '7':

                                        leftUpCtrl.doClick();

                                        break;

                                case 'w':

                                case 'W':

                                case '8':

                                        verticalUpCtrl.doClick();

                                        break;

                                case 'e':

                                case 'E':

                                case '9':

                                        rightUpCtrl.doClick();

                                        break;

                                case 'a':

                                case 'A':

                                case '4':

                                        leftOffCtrl.doClick();

                                        break;

                                case 's':

                                case 'S':

                                case '5':

                                        verticalOffCtrl.doClick();

                                        break;

                                case 'd':

                                case 'D':

                                case '6':

                                        rightOffCtrl.doClick();

                                        break;

                                case 'z':

                                case 'Z':

                                case '1':

                                        leftDownCtrl.doClick();

                                        break;

                                case 'x':

                                case 'X':

                                case '2':

                                        verticalDownCtrl.doClick();

                                        break;

                                case 'c':

                                case 'C':

                                case '3':

                                        rightDownCtrl.doClick();

                                        break;

                                default:

                                        System.out.println("Unknown keystroke: '" + (char)typed + "'");

                        }

                }

                

        }

        

        private class OmniButtonListener implements ActionListener{

                @Override

                public void actionPerformed(ActionEvent arg0) {

                        

                        if(arg0.getSource() == killAll){

                                if(DEBUG) System.out.println("Stop all pressed!");

                                myZeppelin.stopAll();

                                resetState();

                                

                        } else if (arg0.getSource() == forwardCtrl){

                                if(DEBUG) System.out.println("Forward pressed!");

                                myZeppelin.incrementForward();

                                

                        } else if (arg0.getSource() == turnRCtrl){

                                if(DEBUG) System.out.println("Turn right pressed!");

                                //myZeppelin.turnRight();

                                myZeppelin.turnLeft();

                                

                        } else if (arg0.getSource() == turnLCtrl){

                                if(DEBUG) System.out.println("Turn left pressed!");

                                //myZeppelin.turnLeft();

                                myZeppelin.turnRight();

                                

                        } else if (arg0.getSource() == rightUpCtrl){

                                if(DEBUG) System.out.println("Right incr. pressed!");

                                //myZeppelin.incrementRight();

                                myZeppelin.incrementLeft();

                                

                        } else if (arg0.getSource() == rightOffCtrl){

                                if(DEBUG) System.out.println("Right off pressed!");

                                //myZeppelin.zeroRight();

                                myZeppelin.zeroLeft();

                                

                        } else if (arg0.getSource() == rightDownCtrl){

                                if(DEBUG) System.out.println("Right decr. pressed!");

                                //myZeppelin.decrementRight();

                                myZeppelin.decrementLeft();

                                

                        } else if (arg0.getSource() == backCtrl){

                                if(DEBUG) System.out.println("Backward pressed!");

                                myZeppelin.decrementForward();

                                

                        } else if (arg0.getSource() == leftUpCtrl){

                                if(DEBUG) System.out.println("Left incr. pressed!");

                                //myZeppelin.incrementLeft();

                                myZeppelin.incrementRight();

                                

                        } else if (arg0.getSource() == leftOffCtrl){

                                if(DEBUG) System.out.println("Left off pressed!");

                                //myZeppelin.zeroLeft();

                                myZeppelin.zeroRight();

                                

                        } else if (arg0.getSource() == leftDownCtrl){

                                if(DEBUG) System.out.println("Left decr. pressed!");

                                //myZeppelin.decrementLeft();

                                myZeppelin.decrementRight();

                                

                        } else if (arg0.getSource() == verticalUpCtrl){

                                if(DEBUG) System.out.println("Bottom incr. pressed!");

                                myZeppelin.incrementBottom();

                                

                        } else if (arg0.getSource() == verticalOffCtrl){

                                if(DEBUG) System.out.println("Bottom off pressed!");

                                myZeppelin.zeroBottom();

                                

                        } else if (arg0.getSource() == verticalDownCtrl){

                                if(DEBUG) System.out.println("Bottom decr. pressed!");

                                myZeppelin.decrementBottom();

                                

                        } else if (arg0.getSource() == autoHeight){

                                if(DEBUG) System.out.println("Auto set height pressed!");

                                disableVerticalControl();

                                myZeppelin.autoHeight();

                                

                        } else if (arg0.getSource() == manualHeight){

                                if(DEBUG) System.out.println("Manual height pressed!");

                                enableVerticalControl();

                                myZeppelin.manualHeight();

                                

                        } else {

                                if(DEBUG) System.out.println("Unknown button pressed!");

                        }

                        

                        updateGUI();

                }

        }

}

Zeppelin.java

// CSE 466 Blimp Project

// 12-14-2011

// Peter Dwersteg

// Michael Falcone

// Jaylen VanOrden

public class Zeppelin implements SerialObserver {

        

        private static final String COM_PORT = "COM4";

        private static final boolean DEBUG = true;

        

        private SerialHandler mySerial;

        

        private int leftFan         = 0;

        private int rightFan         = 0;

        private int bottomFan         = 0;

        private int altitude        = 0;

        

        private ZeppelinObserver myObs;

        

        public Zeppelin(){                

                // initialize the serial connection

                mySerial = new SerialHandler(COM_PORT);

                mySerial.init();

                mySerial.setSerialObs(this);

        }

        

        // Modifier methods

        public void setZeppelinObserver(ZeppelinObserver theObserver){

                myObs = theObserver;

        }

        

        public void incrementLeft(){

                if(leftFan >= ZH.MOTOR_VEL_HIGHEST){

                        // do nothing

                } else {

                        leftFan++;

                        sendLeft();

                }

        }

        

        public void decrementLeft(){

                if(leftFan <= -1 * ZH.MOTOR_VEL_HIGHEST){

                        // do nothing

                } else {

                        leftFan--;

                        sendLeft();

                }

        }

        

        public void zeroLeft(){

                leftFan = 0;

                sendLeft();

        }

        

        public void incrementRight(){

                if(rightFan >= ZH.MOTOR_VEL_HIGHEST){

                        // do nothing

                } else {

                        rightFan++;

                        sendRight();

                }

        }

        

        public void decrementRight(){

                if(rightFan <= -1 * ZH.MOTOR_VEL_HIGHEST){

                        // do nothing

                } else {

                        rightFan--;

                        sendRight();

                }

        }

        

        public void zeroRight(){

                rightFan = 0;

                sendRight();

        }

        public void incrementBottom(){

                if(bottomFan >= ZH.MOTOR_VEL_HIGHEST){

                        // do nothing

                } else {

                        bottomFan++;

                        sendBottom();

                }

        }

        

        public void decrementBottom(){

                if(bottomFan <= -1 * ZH.MOTOR_VEL_HIGHEST){

                        // do nothing

                } else {

                        bottomFan--;

                        sendBottom();

                }

        }

        

        public void zeroBottom(){

                bottomFan = 0;

                sendBottom();

        }

        

        public void incrementForward(){

                if(rightFan >= ZH.MOTOR_VEL_HIGHEST && leftFan >= ZH.MOTOR_VEL_HIGHEST){

                        // do nothing

                } else {

                        if(rightFan >= ZH.MOTOR_VEL_HIGHEST){

                                // right is at max, so increment left

                                incrementLeft();

                        } else if (leftFan >= ZH.MOTOR_VEL_HIGHEST){

                                // left is at max, so increment right

                                incrementRight();

                        } else {

                                // neither is at max, so decrement both

                                if(leftFan == rightFan){

                                        // If these are equal, get both of them at once

                                        rightFan++;

                                        leftFan++;

                                        sendForward();

                                } else {

                                        // Otherwise, decrement them seperately

                                        incrementRight();

                                        incrementLeft();

                                }

                        }

                }

        }

        

        public void decrementForward(){

                if(rightFan <= -1 * ZH.MOTOR_VEL_HIGHEST && leftFan <= -1 * ZH.MOTOR_VEL_HIGHEST){

                        // do nothing

                } else {

                        if(rightFan <= -1 * ZH.MOTOR_VEL_HIGHEST){

                                // right is at max neg, so decrement left

                                decrementLeft();

                        } else if (leftFan <= -1 * ZH.MOTOR_VEL_HIGHEST){

                                // left is at max, so decrement right

                                decrementRight();

                        } else {

                                // neither is at max, so decrement both

                                if(leftFan == rightFan){

                                        // If these are equal, get both of them at once

                                        rightFan--;

                                        leftFan--;

                                        sendForward();

                                } else {

                                        // Otherwise, decrement them seperately

                                        decrementRight();

                                        decrementLeft();

                                }

                        }

                }

        }

        

        public void turnLeft(){

                incrementRight();

                decrementLeft();

        }

        

        public void turnRight(){

                incrementLeft();

                decrementRight();

        }

        

        public void stopAll(){

                sendKillAll();

                leftFan = 0;

                rightFan = 0;

                bottomFan = 0;

        }

        

        public void autoHeight(){

                sendStartPolling();

                bottomFan = 0;

        }

        

        public void manualHeight(){

                sendStopPolling();

                bottomFan = 0;

        }

        

        // Send methods

        

        private void sendMessage(int msg){

                if(DEBUG) System.out.println("Sending msg: " + ZH.command2String(msg));

                mySerial.writeByte(msg);

                

        }

        

        private void sendLeft(){

                sendMessage(ZH.M_SND_MOTOR_CMD(ZH.MOTOR_ID_LEFT,

                                (leftFan >= 0)?            ZH.MOTOR_DIR_FORWARD : ZH.MOTOR_DIR_REVERSE,

                                Math.abs(leftFan)));

        }

        

        private void sendRight(){

                sendMessage(ZH.M_SND_MOTOR_CMD(ZH.MOTOR_ID_RIGHT,

                                (rightFan >= 0)?        ZH.MOTOR_DIR_FORWARD : ZH.MOTOR_DIR_REVERSE,

                                Math.abs(rightFan)));

        }

        

        private void sendBottom(){

                sendMessage(ZH.M_SND_MOTOR_CMD(ZH.MOTOR_ID_BOTTOM,

                                (bottomFan >= 0)?        ZH.MOTOR_DIR_FORWARD : ZH.MOTOR_DIR_REVERSE,

                                Math.abs(bottomFan)));

        }

        

        private void sendForward(){

                sendMessage(ZH.M_SND_MOTOR_CMD(ZH.MOTOR_ID_FORWARD,

                                (rightFan >= 0)?        ZH.MOTOR_DIR_FORWARD : ZH.MOTOR_DIR_REVERSE,

                                Math.abs(rightFan)));

        }

        

        private void sendKillAll(){

                sendMessage(ZH.M_SND_KILL_ALL());

        }

        

        private void sendStartPolling(){

                sendMessage(ZH.M_SND_SENSOR_RQST(ZH.SENSOR_IR, ZH.SENSOR_IR_START_POLLING));

        }

        

        private void sendStopPolling(){

                sendMessage(ZH.M_SND_SENSOR_RQST(ZH.SENSOR_IR, ZH.SENSOR_IR_STOP_POLLING));

        }

        

        // Accessor methods

        

        public int getLeftFanVel(){

                return leftFan;

        }

        

        public int getRightFanVel(){

                return rightFan;

        }

        

        public int getBottomFanVel(){

                return bottomFan;

        }

        

        public int getAltitude(){

                return altitude;

        }

        @Override

        public void gotData(int newData) {

                altitude = newData;

                if(myObs !=null){

                        myObs.updateAltitude(newData);

                }

        }

}

SerialHandler.java

// CSE 466 Blimp Project

// 12-14-2011

// Peter Dwersteg

// Michael Falcone

// Jaylen VanOrden

// Based on sample code for gnu.io.SerialPort library

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.util.Random;

import java.util.concurrent.ConcurrentLinkedQueue;

import gnu.io.CommPort;

import gnu.io.CommPortIdentifier;

import gnu.io.SerialPort;

        public class SerialHandler{

                

                private String myComPort;

                private Random myRand;

                private SerialObserver myObs;

                private SerialReader myReader;

                private ConcurrentLinkedQueue<Integer> outQueue;

                

                public SerialHandler(String comPort){

                        myComPort = comPort;

                        myRand = new Random();

                        myReader = null;

                        outQueue = new ConcurrentLinkedQueue<Integer>();

                }

                

                public void init(){

                        try {

                                connect(myComPort);

                        } catch (Exception e) {

                                e.printStackTrace();

                        }

                        

                        SerialReader.setObs(myObs);

                }

                

                public void setSerialObs(SerialObserver newObs){

                        myObs = newObs;

                        SerialReader.setObs(myObs);

                }

                

                // Writes the low-order bits of the passed int

                public void writeByte(int toWrite){

                        System.out.println("to serial:\t" + toWrite);

                        outQueue.add(new Integer(toWrite));

                        return;

                }

                

                void connect ( String portName ) throws Exception

            {

                CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);

                if ( portIdentifier.isCurrentlyOwned() )

                {

                    System.out.println("Error: Port is currently in use");

                }

                else

                {

                    CommPort commPort = portIdentifier.open(this.getClass().getName(),2000);

                   

                    if ( commPort instanceof SerialPort )

                    {

                        SerialPort serialPort = (SerialPort) commPort;

                        serialPort.setSerialPortParams(57600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);

                       

                        InputStream in = serialPort.getInputStream();

                        OutputStream out = serialPort.getOutputStream();

                       

                        (new Thread(new SerialReader(in))).start();

                        (new Thread(new SerialWriter(out, outQueue))).start();

                    }

                    else

                    {

                        System.out.println("Error: Only serial ports are handled by this example.");

                    }

                }    

            }

                

            public static class SerialWriter implements Runnable

            {

                    private static final int SERIAL_DELAY = 750;

                OutputStream out;

                ConcurrentLinkedQueue<Integer> myOutQueue;

                private static boolean DEBUG = true;

               

                public SerialWriter ( OutputStream out , ConcurrentLinkedQueue<Integer> outQueue)

                {

                    this.out = out;

                    myOutQueue = outQueue;

                    System.out.println("SerialWriter start");

                }

               

                public void run ()

                {

                        System.out.println("SerialWriter run");

                    try

                    {                

                        while(true){

                                if(!myOutQueue.isEmpty()){

                                        int toPut = myOutQueue.remove().intValue();

                                        

                                        if(DEBUG) System.out.println("Writing: " + toPut);

                                   

                                        this.out.write(toPut);

                                }

                                

                                    try {

                                                        Thread.sleep(SERIAL_DELAY);

                                                } catch (InterruptedException e) {

                                                        e.printStackTrace();

                                                }

                        }

     

                    }

                    catch ( IOException e )

                    {

                        e.printStackTrace();

                    }            

                }

            }

                

                private static class SerialReader implements Runnable

            {

                        

                private static InputStream in;

                private static BufferedReader myReader;

                private static SerialObserver myObs;

                private static boolean DEBUG = true;

               

                public SerialReader ( InputStream in )

                {

                    this.in = in;

                    myReader = new BufferedReader(new InputStreamReader (in));

                    System.out.println("SerialReader start");

                }

               

                public static void setObs(SerialObserver newObs){

                        myObs = newObs;

                }

               

                public void run ()

                {

                        System.out.println("SerialReader run");

                    try

                    {

                            while(true){

                                    if(myReader.ready()){

                                            int nextInt = myReader.read();

                                            

                                            if(myObs != null){

                                                    myObs.gotData(nextInt);

                                                    if(DEBUG) System.out.println("Read:    " + nextInt);

                                            } else {

                                                    System.out.println("Dropping int: " + nextInt);

                                            }

                                    }

                                    

                            }

                    }

                    catch ( IOException e )

                    {

                        e.printStackTrace();

                    }            

                }

           

            }

        }

ZH.java

// CSE 466 Blimp Project

// 12-14-2011

// Peter Dwersteg

// Michael Falcone

// Jaylen VanOrden

// A header-file-like class that defines constants and 'macros' for blimp data sending

public class ZH {

        // Motor ID constants

        public static final int MOTOR_ID_ALL                =        0;        // Mostly used for 'all-stop' command

                                                                                                                // When stopped, also stop all sensors

        public static final int MOTOR_ID_NA_1                =        1;        //Unused

        public static final int MOTOR_ID_NA_2                =        2;        //Unused

        public static final int MOTOR_ID_NA_3                =        3;        //Unused

        public static final int MOTOR_ID_BOTTOM                =        4;

        public static final int MOTOR_ID_LEFT                =        5;

        public static final int MOTOR_ID_RIGHT                =        6;

        public static final int MOTOR_ID_FORWARD        =        7;

        // Motor direction

        public static final int MOTOR_DIR_FORWARD        =        0;

        public static final int MOTOR_DIR_REVERSE        =        1;

        // Motor velocity

        // Gets 3 bits, so range is 0 (off) to 7 (full on)

        // Defines below are not necessary for use, can simply

        // use numbers.  They are included below for clarity and

        // convenience only.

        public static final int MOTOR_VEL_OFF                =        0;

        public static final int MOTOR_VEL_LOWEST        =        1;

        public static final int MOTOR_VEL_LOWER                =        2;

        public static final int MOTOR_VEL_LOW                =        3;

        public static final int MOTOR_VEL_MEDIUM        =        4;

        public static final int MOTOR_VEL_HIGH                =        5;

        public static final int MOTOR_VEL_HIGHER        =        6;

        public static final int MOTOR_VEL_HIGHEST        =        7;

        // Sensor types

        public static final int SENSOR_IR                =                0;

        public static final int SENSOR_E_FIELD        =                1;

        public static final int SENSOR_COMPASS        =                2;

        public static final int SENSOR_BATTERY        =                3;

        public static final int SENSOR_NA_4                =                4;        //Unused

        public static final int SENSOR_NA_5                =                5;        //Unused

        public static final int SENSOR_NA_6                =                6;        //Unused

        public static final int SENSOR_NA_7                =                7;        //Unused

        public static final int SENSOR_NA_8                =                8;        //Unused

        public static final int SENSOR_NA_9                =                9;        //Unused

        public static final int SENSOR_NA_10        =                10;        //Unused

        public static final int SENSOR_NA_11        =                11;        //Unused

        public static final int SENSOR_NA_12        =                12;        //Unused

        public static final int SENSOR_NA_13        =                13;        //Unused

        public static final int SENSOR_NA_14        =                14;        //Unused

        public static final int SENSOR_NA_15        =                15;        //Unused

        // IR Sensor IDs

        public static final int SENSOR_IR_NONE                =                0;

        public static final int SENSOR_IR_START_POLLING =        1;

        public static final int SENSOR_IR_STOP_POLLING        =        2;

        public static final int SENSOR_IR_FRONT                =                3;//0

        public static final int SENSOR_IR_BACK                =                4;//1

        public static final int SENSOR_IR_RIGHT                =                5;//2

        public static final int SENSOR_IR_LEFT                =                6;//3

        public static final int SENSOR_IR_BOTTOM        =                7;//4

        // E-Field Sensor IDs

        public static final int SENSOR_E_FIELD_1        =        0;

        public static final int SENSOR_E_FIELD_2        =        1;

        // Control message construction macros

        public static final int M_SND_MOTOR_CMD(int id, int dir, int vel){

                return ((vel << 5) | (dir << 4) | (id << 1) | 0x1 );

        }

        public static final int M_SND_KILL_ALL(){

                return M_SND_MOTOR_CMD(MOTOR_ID_ALL, MOTOR_DIR_FORWARD, MOTOR_VEL_OFF);

        }

        public static final int M_SND_SENSOR_RQST_NO_ID(int type){

                return (type << 1);

        }

        public static final int M_SND_SENSOR_RQST(int type, int id){

                return ((type << 1) | (id << 5));

        }

        public static String command2String(int msg){

                

                if(M_IS_MOTOR_MSG(msg)){

                        String motor_id = "";

                        

                        switch(M_GET_MOTOR_ID(msg)){

                                case MOTOR_ID_ALL:

                                        motor_id = "ALL";

                                        break;

                                case MOTOR_ID_BOTTOM:

                                        motor_id = "BOTTOM";

                                        break;

                                case MOTOR_ID_FORWARD:

                                        motor_id = "FORWARD";

                                        break;

                                case MOTOR_ID_LEFT:

                                        motor_id = "LEFT";

                                        break;

                                case MOTOR_ID_RIGHT:

                                        motor_id = "RIGHT";

                                        break;

                                default:

                                        motor_id = "UNKNOWN";

                                        break;

                        }

                        

                        int motorVEL = M_GET_MOTOR_VEL(msg);

                        int motorDIR = M_GET_MOTOR_DIR(msg);

                        

                        return "Motor command for " + motor_id + " to go " +

                                ((motorDIR == MOTOR_DIR_FORWARD)? " forward " : " backward ") +

                                " at speed: " + motorVEL;

                        

                } else {

                        return "Sensor command of some kind... ask me later!";

                }

        }

        

        // Control parsing macros

        public static final boolean M_IS_KILL_ALL(int msg){

                return (msg == 0x1);

        }

        public static final boolean M_IS_MOTOR_MSG(int msg){

                return (msg & 0x1) == 1;

        }

        public static final int M_GET_MOTOR_ID(int msg){

                return ((msg >> 1) & 0x7);

        }

        public static final int M_GET_MOTOR_DIR(int msg){

                return ((msg >> 4) & 0x1);

        }

        public static final int M_GET_MOTOR_VEL(int msg){

                return ((msg >> 5) & 0x7);

        }

        public static final boolean M_IS_SENSOR_MSG(int msg){

                return ((msg & 0x1) == 0x0);

        }

        

        public static final int M_GET_SENSOR_TYPE(int msg){

                return ((msg >> 1) & 0xF);

        }

        

        public static final int M_GET_IR_ID(int msg){

                return ((msg >> 5) & 0x7);

        }

        

        public static final int M_GET_E_FIELD_ID(int msg){

                return ((msg >> 5) & 0x1);

        }

}

SerialObserver.java

// CSE 466 Blimp Project

// 12-14-2011

// Peter Dwersteg

// Michael Falcone

// Jaylen VanOrden

public interface SerialObserver {

        public void gotData(int newData);

}

ZeppelinObserver.java

// CSE 466 Blimp Project

// 12-14-2011

// Peter Dwersteg

// Michael Falcone

// Jaylen VanOrden

public interface ZeppelinObserver {

        public void updateAltitude(int newAltitude);

}


Appendix C - MSP430 5510 software

mainframe.c

// CSE 466 Blimp Lab

//

// 12/14/2011

//

// Peter Dwersteg

// Michael Falcone

// Jaylen VanOrden

#include <msp430f5510.h>

#include <stdint.h>

#include "BlimpComm.h"

//Function Declarations

void processHACKmsg(uint8_t rx);

void processIRmsg(uint8_t rx);

void IRStateChange();

void setIR(uint8_t setting);

void killAll();

volatile int IR_SAMPLE_COUNT = 0;

volatile int EMERGENCY = 0;

volatile uint8_t rxB                                 = 0x0;

volatile uint8_t freshReceive                = 0x0;

// Initial motor and sensor settings

#define FAN_PWR_LEVELS                                 7

uint8_t FAN_TIMER                                         = 1;        //1,2,3,4,5,6,7

uint8_t DUMMY_COUNTER                                = 0;

uint8_t FAN_VEL_LEFT                                 = MOTOR_VEL_OFF;

uint8_t FAN_VEL_RIGHT                                 = MOTOR_VEL_OFF;

uint8_t FAN_VEL_BOTTOM                                 = MOTOR_VEL_OFF;

uint8_t FAN_DIR_LEFT                                 = MOTOR_DIR_FORWARD;

uint8_t FAN_DIR_RIGHT                                 = MOTOR_DIR_FORWARD;

uint8_t FAN_DIR_BOTTOM                                 = MOTOR_DIR_FORWARD;

// Initial IR polling sensor settings

uint8_t POLL_IR_NOW                                        = 0;

uint8_t CURRENT_IR_POLLED                        = SENSOR_IR_BOTTOM;

uint8_t IR_TIMER                                        = 0;

// Most recent IR values

uint16_t IR_FRONT                                        = 0;

uint16_t IR_BACK                                                = 0;

uint16_t IR_RIGHT                                        = 0;

uint16_t IR_LEFT                                                = 0;

uint16_t IR_BOTTOM                                        = 0;

uint16_t IR_CURRENT_READING                        = 0;

uint16_t IR_CALIBRATION                                = 0;

void main(void)

{        

  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

 

 //************** SET DCO FREQUENCY ************//

  UCSCTL3 = SELREF_2;                       // Set DCO FLL reference = REFO

  UCSCTL4 |= SELA_2;                        // Set ACLK = REFO

  UCSCTL0 = 0x0000;                         // Set lowest possible DCOx, MODx

 

  // Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize

  do

  {

    UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);

                                            // Clear XT2,XT1,DCO fault flags

    SFRIFG1 &= ~OFIFG;                      // Clear fault flags

  }while (SFRIFG1&OFIFG);                   // Test oscillator fault flag

        

  __bis_SR_register(SCG0);                  // Disable the FLL control loop

  UCSCTL1 = DCORSEL_5;                      // Select DCO range 16MHz operation

  UCSCTL2 |= 255; //249                     // Set DCO Multiplier for 8MHz

                                            // (N + 1) * FLLRef = Fdco

                                            // (249 + 1) * 32768 = 8MHz

  __bic_SR_register(SCG0);                  // Enable the FLL control loop

  // Worst-case settling time for the DCO when the DCO range bits have been

  // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx

  // UG for optimization.

  // 32 x 32 x 8 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle

  __delay_cycles(250000);

 

  P4SEL |= BIT4+BIT5;                        // P4.4,5 = USCI_A0 TXD/RXD

  UCA1CTL1 |= UCSWRST;                      // **Put state machine in reset**

  UCA1CTL1 |= UCSSEL_2;                     // SMCLK

  UCA1BR0 = 54;                              // 1MHz 9600 (see User's Guide)

  UCA1BR1 = 0;                              // 1MHz 9600

  //UCA0MCTL = UCBRS_0 + UCBRF_13 + UCOS16;   // Modln UCBRSx=0, UCBRFx=0,

                                            // over sampling

  UCA1MCTL |= UCBRS_0 + UCBRF_10 + UCOS16;

  UCA1CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**

  UCA1IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt

        // TimerA Setup

  TA0CCTL0 |= CCIE;

  TA0CTL |= TASSEL_2 + ID_3 + MC_1 + TACLR;  // SMCLK, upmode, clear TAR, /8 clock divider

  TA0CCR0 = 1024;                                                         // Slowest interrupt rate

 

  // Fan setup

  P1OUT |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5;        // All fan pins to high

  P1DIR |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5;        // All fan pins to output

 

  // IR setup

  P2DIR |= BIT0;

  PJDIR |= BIT0 + BIT1;

  P1DIR |= BIT6;

  P2OUT |= BIT0;

  P5DIR |= BIT1;

          

 //************** SET UP ADC10 *******************//

  P6SEL |= 0x01;                            // P6.0 ADC option select

  ADC10CTL0 |= ADC10SHT_4 + ADC10ON;        // Sampling time, ADC12 on

  ADC10CTL1 |= ADC10SHP;                          // Use sampling timer

  ADC10IE |= 0x01;                          // Enable interrupt

  ADC10CTL0 |= ADC10ENC;                                        // Enable conversion

  setIR(SENSOR_IR_BOTTOM);                                        // Turn on bottom LED

 

 //***********************************************//

  __bis_SR_register(GIE);       // Enter LPM0, interrupts enabled

 

  while(1){                    

          if(freshReceive != 0x0){

                  if(M_IS_KILL_ALL(rxB)){

                          killAll();

                  } else if(M_IS_MOTOR_MSG(rxB)){

                          // This is a motor command!

                          switch(M_GET_MOTOR_ID(rxB)){

                                case MOTOR_ID_BOTTOM :

                                        FAN_VEL_BOTTOM = M_GET_MOTOR_VEL(rxB);

                                        FAN_DIR_BOTTOM = M_GET_MOTOR_DIR(rxB);

                                        break;

                                case MOTOR_ID_RIGHT :

                                        FAN_VEL_RIGHT = M_GET_MOTOR_VEL(rxB);

                                        FAN_DIR_RIGHT = M_GET_MOTOR_DIR(rxB);

                                        break;

                                case MOTOR_ID_ALL :

                                        FAN_VEL_BOTTOM = M_GET_MOTOR_VEL(rxB);

                                        FAN_DIR_BOTTOM = M_GET_MOTOR_DIR(rxB);

                                        // No break here!  Grab the right and left commands below

                                case MOTOR_ID_FORWARD :

                                        FAN_VEL_RIGHT = M_GET_MOTOR_VEL(rxB);

                                        FAN_DIR_RIGHT = M_GET_MOTOR_DIR(rxB);

                                        // No break here!  Grab the left command below

                                case MOTOR_ID_LEFT :

                                        FAN_VEL_LEFT = M_GET_MOTOR_VEL(rxB);

                                        FAN_DIR_LEFT = M_GET_MOTOR_DIR(rxB);

                                        break;

                                default:

                                        //

                                        break;

                                  }

                  } else if(M_IS_SENSOR_MSG(rxB)){

                          // This is a sense command!

                          switch(M_GET_SENSOR_TYPE(rxB)) {

                                  case SENSOR_IR :

                                          processIRmsg(rxB);

                                          break;

                                  case SENSOR_HACK:

                                          processHACKmsg(rxB);

                                          break;

                                  default:

                                          break;

                          }

                          

                  } else {

                          // Logically impossible...

                  }

                  freshReceive = 0x0;

          }

          

  }

}

// To be called by IR polling loop

void setIR(uint8_t setting){

        

        uint8_t pj1 = 1, pj0 = 1, p16 = 1;

        

        switch(setting) {

                case(SENSOR_IR_FRONT) :

                        pj1 = 0;

                        pj0 = 0;

                        p16 = 0;

                        break;

                case(SENSOR_IR_BACK) :

                        pj1 = 0;

                        pj0 = 0;

                        p16 = 1;        

                        break;

                case(SENSOR_IR_RIGHT) :

                        pj1 = 0;

                        pj0 = 1;

                        p16 = 0;

                        break;

                case(SENSOR_IR_LEFT) :

                        pj1 = 0;

                        pj0 = 1;

                        p16 = 1;

                        break;        

                case(SENSOR_IR_BOTTOM) :

                        pj1 = 1;

                        pj0 = 0;

                        p16 = 0;

                        break;

                default :

                        // Turn off all sensors

                        pj1 = 1;

                        pj0 = 1;

                        p16 = 1;

                        break;

        }

        

        if(pj1 == 1)

                PJOUT |= BIT1;

        else

                PJOUT &= ~BIT1;

                

        if(pj0 == 1)

                PJOUT |= BIT0;

        else

                PJOUT &= ~BIT0;

        

        if(p16 == 1)

                P1OUT |= BIT6;

        else

                P1OUT &= ~BIT6;

}

//Process a "hack" message

//Only meant for debug purposes to take statistics on autonomous altitude control mode

void processHACKmsg(uint8_t rx) {

        

        switch(M_GET_HACK_ID(rx)) {

                case(SENSOR_HACK_ALT_LVL) :

                        // This hack modifies the altitude ir level to be

                        // 15/16 of what it used to be

                        IR_CALIBRATION = (IR_CALIBRATION  >> 4) + (IR_CALIBRATION  >> 3) +

                                                        (IR_CALIBRATION  >> 2) + (IR_CALIBRATION  >> 1);

                        break;

                default:

                        break;

        }

}

//Process an IR subsystem command message

void processIRmsg(uint8_t rx) {

        

        switch(M_GET_IR_ID(rx)) {

                case(SENSOR_IR_START_POLLING) :

                        // Set the flag to start IR polling

                        POLL_IR_NOW = 1;

                        IR_CALIBRATION = 0;

                        break;

                case(SENSOR_IR_STOP_POLLING) :

                        // Clear the flag to stop IR polling

                        POLL_IR_NOW = 0;

                        break;

                case(SENSOR_IR_FRONT) :

                        // Send back front reading

                        UCA1TXBUF = IR_FRONT;

                        break;

                case(SENSOR_IR_BACK) :

                        // Send back back reading

                        UCA1TXBUF = IR_BACK;

                        break;

                case(SENSOR_IR_RIGHT) :

                        // Send back right reading

                        UCA1TXBUF = IR_RIGHT;

                        break;

                case(SENSOR_IR_LEFT) :

                        // Send back left reading

                        UCA1TXBUF = IR_LEFT;

                        break;        

                case(SENSOR_IR_BOTTOM) :

                        // Send back bottom reading

                        UCA1TXBUF = IR_BOTTOM;

                        break;

                default :

                        // Stop polling

                        

                        break;

        }

}

// IR Sampling Method

void IRStateChange() {

        // IR polling code

        if(POLL_IR_NOW) {

        

                /*if(IR_TIMER > 201) {

                        IR_TIMER = 0;

                }*/

                // positive sample

                if(IR_TIMER == 0) {

                        setIR(CURRENT_IR_POLLED);

                } else if(IR_TIMER == 100) {

                        // sample

                }

                

                if(IR_TIMER == 101) {

                        setIR(SENSOR_IR_NONE);

                } else if(IR_TIMER == 201) {

                        // sample

                        

                        // switch to next sensor

                        switch(CURRENT_IR_POLLED) {

                                

                                case(SENSOR_IR_FRONT) :

                                        IR_FRONT = IR_CURRENT_READING;

                                        CURRENT_IR_POLLED = SENSOR_IR_BACK;

                                        break;

                                        

                                case(SENSOR_IR_BACK) :

                                        IR_BACK = IR_CURRENT_READING;

                                        CURRENT_IR_POLLED = SENSOR_IR_RIGHT;

                                        break;

                                        

                                case(SENSOR_IR_RIGHT) :

                                        IR_RIGHT = IR_CURRENT_READING;

                                        CURRENT_IR_POLLED = SENSOR_IR_LEFT;

                                        break;

                                        

                                case(SENSOR_IR_LEFT) :

                                        IR_LEFT = IR_CURRENT_READING;        

                                        CURRENT_IR_POLLED = SENSOR_IR_BOTTOM;

                                        break;        

                                        

                                case(SENSOR_IR_BOTTOM) :

                                        IR_BOTTOM = IR_CURRENT_READING;

                                        CURRENT_IR_POLLED = SENSOR_IR_FRONT;

                                        break;

                                        

                                default :

                                        CURRENT_IR_POLLED = SENSOR_IR_BOTTOM;

                                        break;

                        }

                }

        }

}

// Kill all motors and cancel any sensor reading requests

void killAll(){

        // Kill fans

        FAN_VEL_LEFT = 0;

        FAN_VEL_RIGHT = 0;

        FAN_VEL_BOTTOM = 0;

        

        // Kill IR polling

        processIRmsg(M_SND_SENSOR_RQST(SENSOR_IR, SENSOR_IR_STOP_POLLING));

        

        // Kill fans

        FAN_VEL_LEFT = 0;

        FAN_VEL_RIGHT = 0;

        FAN_VEL_BOTTOM = 0;

}

#pragma vector=USCI_A1_VECTOR

__interrupt void USCI_A1_ISR(void)

{

        

  switch(__even_in_range(UCA1IV,4))

  {

  case 0:break;                             // Vector 0 - no interrupt

  case 2:                                   // Vector 2 - RXIFG

    while (!(UCA1IFG&UCTXIFG));             // USCI_A0 TX buffer ready?

   

    rxB = UCA1RXBUF;

    freshReceive = 0x1;

    break;

  case 4:break;                             // Vector 4 - TXIFG

  default: break;

  }

}

// Timer0 CCR0 Interrupt Vector handler

// Used for motor control

#pragma vector=TIMER0_A0_VECTOR

__interrupt void TIMER0_A0_ISR(void){

        P5DIR ^= BIT1;

        

        if(FAN_VEL_LEFT >= FAN_TIMER){

                if(FAN_DIR_LEFT == MOTOR_DIR_FORWARD){

                        P1OUT &= ~BIT2;

                } else {

                        P1OUT &= ~BIT3;

                }

        } else {

                // Idle high

                P1OUT |= BIT2 + BIT3;

        }

        

        if(FAN_VEL_RIGHT >= FAN_TIMER){

                if(FAN_DIR_RIGHT == MOTOR_DIR_FORWARD){

                        P1OUT &= ~BIT4;

                } else {

                        P1OUT &= ~BIT5;

                }

        } else {

                // Idle high

                P1OUT |= BIT4 + BIT5;

        }

        

        if(FAN_VEL_BOTTOM >= FAN_TIMER){

                if(FAN_DIR_BOTTOM == MOTOR_DIR_FORWARD){

                        P1OUT &= ~BIT0;

                } else {

                        P1OUT &= ~BIT1;

                }

        } else {

                // Idle high

                P1OUT |= BIT0 + BIT1;

        }

        

        if(FAN_TIMER < FAN_PWR_LEVELS){

                FAN_TIMER++;

        } else {

                FAN_TIMER = 1;

        }

        // increment the IR timer

        if(POLL_IR_NOW) {

                IR_TIMER++;

        

                if(IR_TIMER > 20){

                        // Do IR sampling

                          if(!(ADC10CTL1 & ADC10BUSY)){

                                  // If we're ready to take another reading

                                    ADC10CTL0 |= ADC10SC;

                          }

                          IR_TIMER = 0;

                }

        }

}

//************************* ADC10 INTERRUPT ********************//

#pragma vector = ADC10_VECTOR

__interrupt void ADC10_ISR(void)

{

        uint16_t blah = ADC10MEM0;

        

        if(IR_SAMPLE_COUNT %2 == 0){

                IR_CURRENT_READING -= blah;

                setIR(SENSOR_IR_NONE);

        } else {

                IR_CURRENT_READING += blah;

                setIR(SENSOR_IR_BOTTOM);

        }

        

        IR_SAMPLE_COUNT++;

        

        if(IR_SAMPLE_COUNT == 32) {

                 

                IR_BOTTOM = IR_CURRENT_READING >> 5;

                IR_SAMPLE_COUNT = 0;

                IR_CURRENT_READING = 0;

                        

                if(IR_CALIBRATION == 0){

                        IR_CALIBRATION = IR_BOTTOM;

                        UCA1TXBUF = (IR_BOTTOM & 0xFF);

                } else {

                        UCA1TXBUF = (IR_BOTTOM & 0xFF);

                        

                        if(IR_BOTTOM >= IR_CALIBRATION) {

                                

                                FAN_VEL_BOTTOM = MOTOR_VEL_HIGHEST;

                                FAN_DIR_BOTTOM = MOTOR_DIR_FORWARD;

                                

                                EMERGENCY = 1;

                        } else {

                                

                                if(EMERGENCY == 1) {

                                        

                                        FAN_VEL_BOTTOM = MOTOR_VEL_OFF;

                                        

                                        EMERGENCY = 0;

                                }

                        }

                }

        }

}

BlimpComm.h

// CSE 466 Blimp Lab

//

// 12/14/2011

//

// Peter Dwersteg

// Michael Falcone

// Jaylen VanOrden

#ifndef BLIMP_COMM_H

#define BLIMP_COMM_H

// Motor ID constants

#define MOTOR_ID_ALL                0        // Mostly used for 'all-stop' command

                                                                // When stopped, also stop all sensors

#define MOTOR_ID_NA_1                1        //Unused

#define MOTOR_ID_NA_2                2        //Unused

#define MOTOR_ID_NA_3                3        //Unused

#define MOTOR_ID_BOTTOM                4

#define MOTOR_ID_LEFT                5

#define MOTOR_ID_RIGHT                6

#define MOTOR_ID_FORWARD        7

// Motor direction

#define MOTOR_DIR_FORWARD        0

#define MOTOR_DIR_REVERSE        1

// Motor velocity

// Gets 3 bits, so range is 0 (off) to 7 (full on)

// Defines below are not necessary for use, can simply

// use numbers.  They are included below for clarity and

// convenience only.

#define MOTOR_VEL_OFF                0

#define MOTOR_VEL_LOWEST        1

#define MOTOR_VEL_LOWER                2

#define MOTOR_VEL_LOW                3

#define MOTOR_VEL_MEDIUM        4

#define MOTOR_VEL_HIGH                5

#define MOTOR_VEL_HIGHER        6

#define MOTOR_VEL_HIGHEST        7

// Sensor types

#define SENSOR_IR                        0

#define SENSOR_E_FIELD                1

#define SENSOR_COMPASS                2

#define SENSOR_BATTERY                3

#define SENSOR_HACK                        4        //Unused

#define SENSOR_NA_5                        5        //Unused

#define SENSOR_NA_6                        6        //Unused

#define SENSOR_NA_7                        7        //Unused

#define SENSOR_NA_8                        8        //Unused

#define SENSOR_NA_9                        9        //Unused

#define SENSOR_NA_10                10        //Unused

#define SENSOR_NA_11                11        //Unused

#define SENSOR_NA_12                12        //Unused

#define SENSOR_NA_13                13        //Unused

#define SENSOR_NA_14                14        //Unused

#define SENSOR_NA_15                15        //Unused

// IR Sensor IDs

#define SENSOR_IR_NONE                        0

#define SENSOR_IR_START_POLLING 1

#define SENSOR_IR_STOP_POLLING        2

#define SENSOR_IR_FRONT                        3//0

#define SENSOR_IR_BACK                        4//1

#define SENSOR_IR_RIGHT                        5//2

#define SENSOR_IR_LEFT                        6//3

#define SENSOR_IR_BOTTOM                7//4

// Hack IDs

#define SENSOR_HACK_ALT_LVL                0

#define SENSOR_HACK_NA_1                1

#define SENSOR_HACK_NA_2                2

#define SENSOR_HACK_NA_3                3

#define SENSOR_HACK_NA_4                4

#define SENSOR_HACK_NA_5                5

#define SENSOR_HACK_NA_6                6

#define SENSOR_HACK_NA_27                7

// E-Field Sensor IDs

#define SENSOR_E_FIELD_1        0

#define SENSOR_E_FIELD_2        1

// Control message construction macros

#define M_SND_MOTOR_CMD(id, dir, vel)        ((vel << 5) | (dir << 4) | (id << 1) | 0x1 )

#define M_SND_KILL_ALL                                        M_SND_MOTOR_CMD(MOTOR_ID_ALL, MOTOR_DIR_FORWARD, MOTOR_VEL_OFF)

#define M_SND_SENSOR_RQST_NO_ID(type)        (type << 1)

#define M_SND_SENSOR_RQST(type, id)                ((type << 1) | (id << 5))

// Control parsing macros

#define M_IS_KILL_ALL(msg)                                (msg == 0x1)

#define M_IS_MOTOR_MSG(msg)                                (msg & 0x1)

#define M_GET_MOTOR_ID(msg)                                ((msg >> 1) & 0x7)

#define M_GET_MOTOR_DIR(msg)                        ((msg >> 4) & 0x1)

#define M_GET_MOTOR_VEL(msg)                        ((msg >> 5) & 0x7)

#define M_IS_SENSOR_MSG(msg)                        ((msg & 0x1) == 0x0)

#define M_GET_SENSOR_TYPE(msg)                        ((msg >> 1) & 0xF)

#define M_GET_HACK_ID(msg)                                ((msg >> 5) & 0x7)

#define M_GET_IR_ID(msg)                                ((msg >> 5) & 0x7)

#define M_GET_E_FIELD_ID(msg)                        ((msg >> 5) & 0x1)

#endif // BLIMP_COMM_H

Appendix D - MSP430 RF2500 Software

main_LinkListen.c

// CSE 466 Blimp Lab

//

// 12/14/2011

//

// Peter Dwersteg

// Michael Falcone

// Jaylen VanOrden

// Based on TI sample code

/*----------------------------------------------------------------------------

 *  Demo Application for SimpliciTI

 *

 *  L. Friedman

 *  Texas Instruments, Inc.

 *----------------------------------------------------------------------------

 */

/******************************************************************************************

  Copyright 2007-2009 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights granted under

  the terms of a software license agreement between the user who downloaded the software,

  his/her employer (which must be your employer) and Texas Instruments Incorporated (the

  "License"). You may not use this Software unless you agree to abide by the terms of the

  License. The License limits your use, and you acknowledge, that the Software may not be

  modified, copied or distributed unless embedded on a Texas Instruments microcontroller

  or used solely and exclusively in conjunction with a Texas Instruments radio frequency

  transceiver, which is integrated into your product. Other than for the foregoing purpose,

  you may not use, reproduce, copy, prepare derivative works of, modify, distribute,

  perform, display or sell this Software and/or its documentation for any purpose.

  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS”

  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY

  WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.

  IN NO EVENT SHALL TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,

  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE

  THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY

  INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST

  DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY

  THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

  Should you have any questions regarding your right to use this Software,

  contact Texas Instruments Incorporated at www.TI.com.

**************************************************************************************************/

#include "bsp.h"

#include "mrfi.h"

#include "nwk_types.h"

#include "nwk_api.h"

#include "bsp_leds.h"

#include "bsp_buttons.h"

#include "virtual_com_cmds.h"

#include "app_remap_led.h"

static void linkFrom(void);

void toggleLED(uint8_t);

// functions to decode motor messages

#define M_IS_MOTOR_MSG(msg)                                (msg & 0x1)

#define M_GET_MOTOR_ID(msg)                                ((msg >> 1) & 0x7)

#define M_GET_MOTOR_DIR(msg)                        ((msg >> 4) & 0x1)

#define M_GET_MOTOR_VEL(msg)                        ((msg >> 5) & 0x7)

#define MOTOR_ID_BOTTOM                4

#define MOTOR_ID_LEFT                5

#define MOTOR_ID_RIGHT                6

#define MOTOR_ID_SIDES                7

#define MOTOR_DIR_FORWARD        0

#define MOTOR_DIR_REVERSE        1

static          uint8_t  sRxTid = 0;

static          linkID_t sLinkID2 = 0;

static volatile uint8_t  sSemaphore = 0;

//static linkID_t sLinkID_Custom;

// The board to connect to is...

addr_t pAddr = {{0x73, 0x31, 0x73, 0x31}};

/* Rx callback handler */

static uint8_t sRxCallback(linkID_t);

void main (void)

{

  BSP_Init();

  COM_Init();

        P2DIR = 0x03;

        P2OUT = 0x00;

        //P2OUT = 0x01;

  /* If an on-the-fly device address is generated it must be done before the

   * call to SMPL_Init(). If the address is set here the ROM value will not

   * be used. If SMPL_Init() runs before this IOCTL is used the IOCTL call

   * will not take effect. One shot only. The IOCTL call below is conformal.

   *

   */

/*#ifdef I_WANT_TO_CHANGE_DEFAULT_ROM_DEVICE_ADDRESS_PSEUDO_CODE

  {

    addr_t lAddr;

    createRandomAddress(&lAddr);

    SMPL_Ioctl(IOCTL_OBJ_ADDR, IOCTL_ACT_SET, &lAddr);

  }

#endif I_WANT_TO_CHANGE_DEFAULT_ROM_DEVICE_ADDRESS_PSEUDO_CODE */

  /* This call will fail because the join will fail since there is no Access Point

   * in this scenario. But we don't care -- just use the default link token later.

   * We supply a callback pointer to handle the message returned by the peer.

   */

  SMPL_Init(sRxCallback);

 

  uint8_t lPort = 0x3E;

  uint8_t rPort = 0x3E;

  smplStatus_t result = SMPL_Commission(&pAddr, lPort, rPort, &sLinkID2);

 

  if(result == SMPL_SUCCESS){

          asm(" NOP");

  } else {

          asm(" NOP");

  }  

  /* turn on LEDs. */

  if (!BSP_LED2_IS_ON())

  {

    toggleLED(2);

  }

  if (!BSP_LED1_IS_ON())

  {

    toggleLED(1);

  }

  /* wait for a button press... */

  /*do {

    if (BSP_BUTTON1() || BSP_BUTTON2())

    {

      break;

    }

  } while (1);*/

  /* never coming back... */

  linkFrom();

  /* but in case we do... */

  while (1) ;

}

static void linkFrom()

{

  uint8_t     msg[2], tid = 0;

  /* Turn off one LED so we can tell the device is now listening.

   * Received messages will toggle the other LED.

   */

  toggleLED(1);

   /* listen for link forever... */

  while (1)

  {

    if (SMPL_SUCCESS == SMPL_LinkListen(&sLinkID2))

    {

      break;

    }

    /* Implement fail-to-link policy here. otherwise, listen again. */

  }

   /* turn on LED1 on the peer in response to receiving a frame. */

   *msg = 0x01;

   /* turn on RX. default is RX off. */

   SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXON, 0);

   while (1)

   {

     /* Wait for a frame to be received. The Rx handler, which is running in

      * ISR thread, will post to this semaphore allowing the application to

      * send the reply message in the user thread.

      */

     /*if (sSemaphore)

     {

       *(msg+1) = ++tid;

       SMPL_Send(sLinkID2, msg, 2);

        Reset semaphore. This is not properly protected and there is a race

        * here. In theory we could miss a message. Good enough for a demo, though.

       

       sSemaphore = 0;

     } */

     

    char justGot = getReadChar();

    if(gotData()){                                // get serial data

            //TXString(&justGot, 1);

            markDataRead();

            

            toggleLED(1);

            

            msg[1] = justGot;                                                        

            SMPL_Send(sLinkID2, msg, sizeof(msg));        // send a byte wireless

    } else {

            toggleLED(2);

            //TXString("X", 1);

    }

     

   }

}

void toggleLED(uint8_t which)

{

  if (1 == which)

  {

    BSP_TOGGLE_LED1();

  }

  else if (2 == which)

  {

    BSP_TOGGLE_LED2();

  }

  return;

}

/* handle received messages */

static uint8_t sRxCallback(linkID_t port)

{

  uint8_t msg[2], len, tid;

  /* is the callback for the link ID we want to handle? */

  if (port == sLinkID2)

  {

    /* yes. go get the frame. we know this call will succeed. */

     if ((SMPL_SUCCESS == SMPL_Receive(sLinkID2, msg, &len)) && len)

     {

       /* Check the application sequence number to detect

        * late or missing frames...

        */

       tid = *(msg+1);

       if (tid)

       {

         if (tid > sRxTid)

         {

           /* we're good. toggle LED */

           toggleLED(*msg);

           sRxTid = tid;

         }

       }

       else

       {

         /* wrap case... */

         if (sRxTid)

         {

           /* we're good. toggle LED */

           toggleLED(*msg);

           sRxTid = tid;

         }

       }

       /* Post to the semaphore to let application know so it sends

        * the reply

        */

       sSemaphore = 1;

       

       

       // right is pin3, low order bit

       // left is pin4, high order bit

       // is it a motor message?

       if (M_IS_MOTOR_MSG(msg[1])) {        

                       if(M_GET_MOTOR_ID(msg[1]) == MOTOR_ID_LEFT) {

                               if(M_GET_MOTOR_DIR(msg[1]) == MOTOR_DIR_REVERSE) {

                                       P2OUT |= 0x02;

                               } else {

                                       P2OUT &= ~0x02;

                               }

                       } else if(M_GET_MOTOR_ID(msg[1]) == MOTOR_ID_RIGHT) {

                               if(M_GET_MOTOR_DIR(msg[1]) == MOTOR_DIR_REVERSE) {

                                       P2OUT |= 0x01;

                               } else {

                                       P2OUT &= ~0x01;

                               }

                       } else if(M_GET_MOTOR_ID(msg[1]) == MOTOR_ID_SIDES) {

                               if(M_GET_MOTOR_DIR(msg[1]) == MOTOR_DIR_REVERSE) {

                                       P2OUT |= 0x03;

                               } else {

                                       P2OUT &= ~0x03;

                               }

                       } else if(msg[1] == 1) {

                               P2OUT = 0;

                       }

       }

               

      //P2OUT = 0x01;        

       

       

       

       

       TXString(&msg[1], 1);

       

       

       

       /* drop frame. we're done with it. */

       return 1;

     }

  }

  /* keep frame for later handling */

  return 0;

}

main_LinkTo.c

// CSE 466 Blimp Lab

//

// 12/14/2011

//

// Peter Dwersteg

// Michael Falcone

// Jaylen VanOrden

// Based on TI sample code

/*----------------------------------------------------------------------------

 *  Demo Application for SimpliciTI

 *

 *  L. Friedman

 *  Texas Instruments, Inc.

 *---------------------------------------------------------------------------- */

/********************************************************************************************

  Copyright 2007-2009 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights granted under

  the terms of a software license agreement between the user who downloaded the software,

  his/her employer (which must be your employer) and Texas Instruments Incorporated (the

  "License"). You may not use this Software unless you agree to abide by the terms of the

  License. The License limits your use, and you acknowledge, that the Software may not be

  modified, copied or distributed unless embedded on a Texas Instruments microcontroller

  or used solely and exclusively in conjunction with a Texas Instruments radio frequency

  transceiver, which is integrated into your product. Other than for the foregoing purpose,

  you may not use, reproduce, copy, prepare derivative works of, modify, distribute,

  perform, display or sell this Software and/or its documentation for any purpose.

  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS”

  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY

  WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.

  IN NO EVENT SHALL TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,

  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE

  THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY

  INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST

  DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY

  THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

  Should you have any questions regarding your right to use this Software,

  contact Texas Instruments Incorporated at www.TI.com.

**************************************************************************************************/

#include "bsp.h"

#include "mrfi.h"

#include "nwk_types.h"

#include "nwk_api.h"

#include "bsp_leds.h"

#include "bsp_buttons.h"

#include "app_remap_led.h"

#include "virtual_com_cmds.h"

//#include "myHeader.h"

static void linkTo(void);

void toggleLED(uint8_t);

static uint8_t  sTxTid=0, sRxTid=0;

static linkID_t sLinkID1 = 0;

//static linkID_t sLinkID_Custom;

// The board to connect to is...

addr_t pAddr = {{0x13, 0x37, 0x13, 0x37}};

/* application Rx frame handler. */

static uint8_t sRxCallback(linkID_t);

#define SPIN_ABOUT_A_SECOND  NWK_DELAY(1000)

void main (void)

{

  BSP_Init();

  COM_Init();

  /* If an on-the-fly device address is generated it must be done before the

   * call to SMPL_Init(). If the address is set here the ROM value will not

   * be used. If SMPL_Init() runs before this IOCTL is used the IOCTL call

   * will not take effect. One shot only. The IOCTL call below is conformal.

   */

   /*

#ifdef I_WANT_TO_CHANGE_DEFAULT_ROM_DEVICE_ADDRESS_PSEUDO_CODE

  {

    addr_t lAddr;

    createRandomAddress(&lAddr);

    SMPL_Ioctl(IOCTL_OBJ_ADDR, IOCTL_ACT_SET, &lAddr);

  }

#endif I_WANT_TO_CHANGE_DEFAULT_ROM_DEVICE_ADDRESS_PSEUDO_CODE */

  /* This call will fail because the join will fail since there is no Access Point

   * in this scenario. But we don't care -- just use the default link token later.

   * We supply a callback pointer to handle the message returned by the peer.

   */

  SMPL_Init(sRxCallback);

  uint8_t lPort = 0x3E;

  uint8_t rPort = 0x3E;

  smplStatus_t result = SMPL_Commission(&pAddr, lPort, rPort, &sLinkID1);

 

  if(result == SMPL_SUCCESS){

          asm(" NOP");

  } else {

          asm(" NOP");

  }

  /* turn on LEDs. */

  if (!BSP_LED2_IS_ON())

  {

    toggleLED(2);

  }

  if (!BSP_LED1_IS_ON())

  {

    toggleLED(1);

  }

  /* wait for a button press... */

  /*do {

    if (BSP_BUTTON1() || BSP_BUTTON2())

    {

      break;

    }

  } while (1);*/

  /* never coming back... */

  linkTo();

  /* but in case we do... */

  while (1) ;

}

static void linkTo()

{

  uint8_t  msg[2], delay = 0;

  while (SMPL_SUCCESS != SMPL_Link(&sLinkID1))

  {

    /* blink LEDs until we link successfully */

    toggleLED(1);

    toggleLED(2);

    SPIN_ABOUT_A_SECOND;

  }

  /* we're linked. turn off red LED. received messages will toggle the green LED. */

  if (BSP_LED2_IS_ON())

  {

    toggleLED(2);

  }

  /* turn on RX. default is RX off. */

  SMPL_Ioctl( IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXON, 0);

  /* put LED to toggle in the message */

  msg[0] = 2;  /* toggle red */

  while (1)

  {

    SPIN_ABOUT_A_SECOND;

    if (delay > 0x00)

    {

      SPIN_ABOUT_A_SECOND;

    }

    if (delay > 0x01)

    {

      SPIN_ABOUT_A_SECOND;

    }

    if (delay > 0x02)

    {

      SPIN_ABOUT_A_SECOND;

    }

    /* delay longer and longer -- then start over */

 //   delay = (delay+1) & 0x03;

    /* put the sequence ID in the message */

    //msg[1] = ++sTxTid;

   

    //msg[1] = 'U';

   

   

   

   

    //TXString("sent", 4);

//    char * justGot = (char*) malloc(sizeof(char));

    char justGot = getReadChar();

    if(gotData()){                                // get serial data

            //TXString(&justGot, 1);

            markDataRead();

            

            toggleLED(1);

            

            msg[1] = justGot;                                                        

            SMPL_Send(sLinkID1, msg, sizeof(msg));        // send a byte wireless

    } else {

            toggleLED(2);

            //TXString("X", 1);

    }

//        free(justGot);    

  }

}

void toggleLED(uint8_t which)

{

  if (1 == which)

  {

    BSP_TOGGLE_LED1();

  }

  else if (2 == which)

  {

    BSP_TOGGLE_LED2();

  }

  return;

}

/* handle received frames. */

static uint8_t sRxCallback(linkID_t port)

{

  uint8_t msg[2], len, tid;

  /* is the callback for the link ID we want to handle? */

  if (port == sLinkID1)

  {

    /* yes. go get the frame. we know this call will succeed. */

     if ((SMPL_SUCCESS == SMPL_Receive(sLinkID1, msg, &len)) && len)  // READ A BYTE WIRELESS

     {

       /* Check the application sequence number to detect

        * late or missing frames...

        */

       tid = *(msg+1);

       if (tid)

       {

         if (tid > sRxTid)

         {

           /* we're good. toggle LED in the message */

           //toggleLED(*msg);

           sRxTid = tid;

         }

       }

       else

       {

         /* the wrap case... */

         if (sRxTid)

         {

           /* we're good. toggle LED in the message */

           //toggleLED(*msg);

           sRxTid = tid;

         }

       }

       /* drop frame. we're done with it. */

       

       //--------------- SEND A BYTE SERIAL ----------------//

       TXString(&msg[1], 1);

       //---------------------------------------------------//

       

       return 1;

     }

  }

  /* keep frame for later handling. */

  return 0;

}

smpl_nwk_config.dat

#

#  Filename:       smpl_nwk_config.dat

#  Revised:        $Date: 2009-02-07 14:21:07 -0700 (Sat, 07 Feb 2009) $

#  Revision:       $Revision: 19010 $

#  Author:         $Author: lfriedman $

#

#  Description:    This file supports the SimpliciTI Customer Configuration for overall network.

#

#  Copyright 2009 Texas Instruments Incorporated. All rights reserved.

#

#  IMPORTANT: Your use of this Software is limited to those specific rights granted under

#  the terms of a software license agreement between the user who downloaded the software,

#  his/her employer (which must be your employer) and Texas Instruments Incorporated (the

#  "License"). You may not use this Software unless you agree to abide by the terms of the

#  License. The License limits your use, and you acknowledge, that the Software may not be

#  modified, copied or distributed unless embedded on a Texas Instruments microcontroller

#  or used solely and exclusively in conjunction with a Texas Instruments radio frequency

#  transceiver, which is integrated into your product. Other than for the foregoing purpose,

#  you may not use, reproduce, copy, prepare derivative works of, modify, distribute,

#  perform, display or sell this Software and/or its documentation for any purpose.

#

#  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS”

#  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY

#  WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.

#  IN NO EVENT SHALL TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,

#  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE

#  THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY

#  INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST

#  DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY

#  THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

#

#  Should you have any questions regarding your right to use this Software,

#  contact Texas Instruments Incorporated at www.TI.com.

# Max hop count

--define=MAX_HOPS=3

# Max hops away from and AP. Keeps hop count and therefore replay

# storms down for sending to and from polling End Devices. Also used

# when joining since the EDs can't be more than 1 hop away.

--define=MAX_HOPS_FROM_AP=1

# Maximum size of Network application payload. Do not change unless

# protocol changes are reflected in different maximum network

# application payload size.

--define=MAX_NWK_PAYLOAD=9

# Maximum size of application payload

--define=MAX_APP_PAYLOAD=10

# Default Link token

--define=DEFAULT_LINK_TOKEN=0x01020304

# Default Join token

--define=DEFAULT_JOIN_TOKEN=0x05060708

# Remove '#' to enable Frequency Agility as active for this build

#--define=FREQUENCY_AGILITY

# Remove '#' to enable application autoacknowledge support. Requires extended API as well

#--define=APP_AUTO_ACK

# Remove '#' to enable Extended API

--define=EXTENDED_API

# Remove '#' corruption to enable security.

#--define=SMPL_SECURE

# Remove '#' to enable NV object support

#--define=NVOBJECT_SUPPORT

# Insert '#' to disable software timer

--define=SW_TIMER

smpl_config.dat

#

#  Filename:       smpl_config.dat

#  Revised:        $Date: 2008-11-18 16:54:54 -0800 (Tue, 18 Nov 2008) $

#  Revision:       $Revision: 18453 $

#  Author:         $Author: lfriedman $

#

#  Description:    This file supports the SimpliciTI Customer Configuration for End Devices.

#

#  Copyright 2008-2009 Texas Instruments Incorporated. All rights reserved.

#

#  IMPORTANT: Your use of this Software is limited to those specific rights granted under

#  the terms of a software license agreement between the user who downloaded the software,

#  his/her employer (which must be your employer) and Texas Instruments Incorporated (the

#  "License"). You may not use this Software unless you agree to abide by the terms of the

#  License. The License limits your use, and you acknowledge, that the Software may not be

#  modified, copied or distributed unless embedded on a Texas Instruments microcontroller

#  or used solely and exclusively in conjunction with a Texas Instruments radio frequency

#  transceiver, which is integrated into your product. Other than for the foregoing purpose,

#  you may not use, reproduce, copy, prepare derivative works of, modify, distribute,

#  perform, display or sell this Software and/or its documentation for any purpose.

#

#  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS”

#  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY

#  WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.

#  IN NO EVENT SHALL TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,

#  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE

#  THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY

#  INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST

#  DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY

#  THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

#

#  Should you have any questions regarding your right to use this Software,

#  contact Texas Instruments Incorporated at www.TI.com.

# Number of connections supported. Each connection supports bi-directional

# communication.  Access Points and Range Extenders can set this to 0 if they

# do not host End Device objects.

--define=NUM_CONNECTIONS=2

# Size of low level queues for sent and received frames. Affects RAM usage

# AP needs larger input frame queue if it is supporting store-and-forward

# clients because the forwarded messages are held here.

--define=SIZE_INFRAME_Q=2

# The output frame queue can be small since Tx is done synchronously. Actually

# 1 is probably enough. If an Access Point device is also hosting an End Device

# that sends to a sleeping peer the output queue should be larger -- the waiting

# frames in this case are held here. In that case the output frame queue should

# be bigger.

--define=SIZE_OUTFRAME_Q=2

# This device's address. The first byte is used as a filter on the CC1100/CC2500

# radios so THE FIRST BYTE MUST NOT BE either 0x00 or 0xFF. Also, for these radios

# on End Devices the first byte should be the least significant byte so the filtering

# is maximally effective. Otherwise the frame has to be processed by the MCU before it

# is recognized as not intended for the device. APs and REs run in promiscuous mode so

# the filtering is not done. This macro intializes a static const array of unsigned

# characters of length NET_ADDR_SIZE (found in nwk_types.h). The quotes (") are

# necessary below unless the spaces are removed.

#--define=THIS_DEVICE_ADDRESS="{0x73, 0x31, 0x73, 0x31}"

--define=THIS_DEVICE_ADDRESS="{0x13, 0x37, 0x13, 0x37}"

--define=END_DEVICE

# For polling End Devices we need to specify that they do so. Uncomment the

# macro definition below if this is a polling device. This field is used

# by the Access Point to know whether to reserve store-and-forward support

# for the polling End Device during the Join exchange.

# --define=RX_POLLS