SSI Embedded Systems Programming  
     Sitemap Contact Us  
   
   
 

    HOME


Outsourcing >

Overview

Customer Satisfaction

Our Engineers

Questions to Ask

Technical Lab

Testimonials

Whitepapers



    


Developing a Controller Using Design Patterns

The following is the source code that goes with the practical example of how to use software design patterns in modeling real-world embedded systems applications. It illustrates how to apply design patterns during the development of a garage door controller. Important benefits of state design patterns are a result: Software Modularity, Code Re-usability, Improved Maintainability, Lower Costs, Faster Time-to-Market. Read the full article: Developing a Controller Using Design Patterns.

Example Source Code

Below is the source code developed for this garage door opener design.  The design was built and testing using version 3.2 of Java’s Eclipse IDE.  A total of five (5) image files were used and placed inside a subdirectory called “Images”, located one level immediately below the location where the class files are generated.  These image files are simply for demonstration purposes to show the garage door controller works. 

The five (5) image files are:
GarageDoorClosed.jpg
GarageDoorOpeningOrClosing.jpg
GarageDoorOpen.jpg
GarageDoorOpener.jpg
GarageDoorSensor.jpg

GarageDoorControllerState.java:
package DesignPatterns.State;
import javax.swing.ImageIcon;

public interface GarageDoorControllerState {
    public void pushButton( StateContext pStateContext );
    public void motorStopped( StateContext pStateContext );
    public boolean tripSensor( StateContext pStateContext );
    public ImageIcon getImage( StateContext pStateContext );
}

Closed.java:
package DesignPatterns.State;
import javax.swing.ImageIcon;

public class Closed implements GarageDoorControllerState {
    private static final String sImageFile = "GarageDoorClosed.jpg";
    public void pushButton( StateContext pStateContext ) {
        pStateContext.setState( new Opening() );
    }
           
    public void motorStopped( StateContext pStateContext ) { }           
    public boolean tripSensor( StateContext pStateContext ) { return( false ); }
           
    public ImageIcon getImage( StateContext pStateContext ) {
        return( new ImageIcon( Closed.class.getResource( "Images/" + sImageFile ) ) );
    }
}

Opening.java:
package DesignPatterns.State;
import javax.swing.ImageIcon;

public class Opening implements GarageDoorControllerState {
    private static final String sImageFile = "GarageDoorOpeningOrClosing.jpg";
    public void pushButton( StateContext pStateContext ) {
        pStateContext.setState( new Closing() );  
    }
           
    public void motorStopped( StateContext pStateContext ) {
        pStateContext.setState( new Open() );
    }
           
    public boolean tripSensor( StateContext pStateContext ) { return( false ); }
    public ImageIcon getImage( StateContext pStateContext ) {
        return( new ImageIcon( Opening.class.getResource( "Images/" + sImageFile ) ) );
    }
}

Open.java:
package DesignPatterns.State;
import javax.swing.ImageIcon;

public class Open implements GarageDoorControllerState {
    private static final String sImageFile = "GarageDoorOpen.jpg";
    public void pushButton( StateContext pStateContext ) {
        pStateContext.setState( new Closing() );
    }
           
    public void motorStopped( StateContext pStateContext ) { }
    public boolean tripSensor( StateContext pStateContext ) { return( false ); }
    public ImageIcon getImage( StateContext pStateContext ) {
        return( new ImageIcon( Open.class.getResource( "Images/" + sImageFile ) ) );
    }
}

Closing.java:
package DesignPatterns.State;
import javax.swing.ImageIcon;

public class Closing implements GarageDoorControllerState {
    private static final String sImageFile = "GarageDoorOpeningOrClosing.jpg";
    public void pushButton( StateContext pStateContext ) {
        pStateContext.setState( new Opening() );
    }

    public void motorStopped( StateContext pStateContext ) {
        pStateContext.setState( new Closed() );
    }
           
    public boolean tripSensor( StateContext pStateContext ) {
        pStateContext.setState( new Opening() );
        return( true );
    }
           
    public ImageIcon getImage( StateContext pStateContext ) {
        return( new ImageIcon( Closing.class.getResource( "Images/" + sImageFile ) ) );
    }
}

StateContext.java:
package DesignPatterns.State;
import javax.swing.ImageIcon;

public class StateContext {
    private GarageDoorControllerState aState;

    public StateContext () { aState = new Closed(); }
    public void setState( GarageDoorControllerState pState ) {
        // In C++, here is where we would do a delete[] aState to avoid memory leaks!
        aState = pState;
    }
              
    public String getStateAsText() {
            String lStateText = "";
            if( aState instanceof Closed ) { lStateText = "Closed"; }
            else if( aState instanceof Closing ) { lStateText = "Closing"; }
            else if( aState instanceof Open ) { lStateText = "Open"; }
            else if( aState instanceof Opening ) { lStateText = "Opening"; }
           
            return( lStateText );
    }
   
    public void pushButton() { aState.pushButton( this ); }
    public void motorStopped() { aState.motorStopped( this ); }
    public boolean tripSensor() { return( aState.tripSensor( this ) ); }
    public ImageIcon getImage() { return( aState.getImage( this ) ); }
}

StateTest.java:
package DesignPatterns.State;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;

public class StateTest extends JPanel implements ActionListener {
    private static final long serialVersionUID = 327686553613107226L;
    private static final String sGarageDoorOpenerFile = "Images/GarageDoorOpener.jpg";
    private static final String sGarageDoorSensorFile = "Images/GarageDoorSensor.jpg";
    private static final int sGarageDoorOpenCloseTime = 10000;
    private static final int sGarageDoorTimerInterval = 100;
    private StateContext aStateContext;
    private JButton aGarageDoorOpenerButton;
    private JLabel aStateImage;
    private JTextArea aStatus;
    private JButton aSensor;
    private Timer aGarageDoorTimer;
    private int aTime = 0;
       
    public StateTest() {
        setLayout( new BorderLayout() );  
        aStateContext = new StateContext();
        aGarageDoorTimer = new Timer( sGarageDoorTimerInterval, this );
       
        // Make the bottom button for the garage door opener
        aGarageDoorOpenerButton = new JButton( new ImageIcon( 
            StateTest.class.getResource( sGarageDoorOpenerFile ) ) );

        aGarageDoorOpenerButton.addActionListener( this );
        aSensor = new JButton( new ImageIcon( StateTest.class.getResource(
            sGarageDoorSensorFile ) ) );
        aSensor.addActionListener( this );
       
        // Make Status area
        aStatus = new JTextArea( 5, 5 );
        aStatus.setEditable( false );       
        JScrollPane lStatusPane = new JScrollPane( aStatus );
       
        // Make something for the center
        JPanel lGarageDoorPanel = new JPanel( new BorderLayout() );
        aStateImage = new JLabel( aStateContext.getImage() );
        lGarageDoorPanel.add( aStateImage, BorderLayout.CENTER );
               
        // Make Panel for the buttons on the RHS!
        JPanel lSouthPanel = new JPanel( new BorderLayout() );
        JPanel lButtonPanel = new JPanel( new BorderLayout() );
        JPanel lTopButtonPanel = new JPanel( new FlowLayout() );
        lTopButtonPanel.add( aGarageDoorOpenerButton );
        JPanel lSensorButtonPanel = new JPanel( new FlowLayout() );
        lSensorButtonPanel.add( aSensor );
        lButtonPanel.add( lTopButtonPanel, BorderLayout.NORTH );
        lButtonPanel.add( lSensorButtonPanel, BorderLayout.SOUTH );
        lSouthPanel.add( lStatusPane, BorderLayout.CENTER );
        lSouthPanel.setBorder( new TitledBorder( "Garage Door Status" ) );
       
        // Add what we have!
        add( lSouthPanel, BorderLayout.SOUTH );
        add( lGarageDoorPanel, BorderLayout.WEST );
        add( lButtonPanel, BorderLayout.CENTER );
       
        aStatus.append( "The Garage Door is Currently:  " +
            aStateContext.getStateAsText() + "\n" );
    }
           
    public static void main( String[] pArguments ) {
        JFrame lApplication = new JFrame( "Garage Door Opener" );
        lApplication.add( new StateTest() );
        lApplication.setSize( 1024, 768 );
        lApplication.setVisible( true );
        lApplication.setLocationRelativeTo( null );
        lApplication.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        lApplication.addWindowListener( new WindowAdapter() {
            public void windowClosing( WindowEvent pEvent ) {
                System.exit( 0 );
            } }); }
           
    public void actionPerformed( ActionEvent pEvent ) {
        if( pEvent.getSource() == aGarageDoorOpenerButton ) {
            aTime = figureOutTime();
            aStateContext.pushButton();
            aGarageDoorTimer.restart();
            updateView();
        }
        else if( pEvent.getSource() == aGarageDoorTimer ) {
            aTime += sGarageDoorTimerInterval;
            if( aTime >= sGarageDoorOpenCloseTime ) {
                aStateContext.motorStopped();
                aGarageDoorTimer.stop();
                updateView();
            }
        }
        else if( pEvent.getSource() == aSensor ) {
            boolean lRetracted = aStateContext.tripSensor();
            if( lRetracted == true ) {
                aTime = figureOutTime();
                aGarageDoorTimer.restart();
                updateView();
            }                                 
        }
    }
           
    private void updateView() {
        aStateImage.setIcon( aStateContext.getImage() );                        
        aStatus.append( "The Garage Door is Currently:  " +
            aStateContext.getStateAsText() + "\n" );
    }
           
    private int figureOutTime() {
        int lTime = 0;
        if( aGarageDoorTimer.isRunning() == true ) {
            lTime = sGarageDoorOpenCloseTime - aTime;
        }
                       
        return( lTime );
    }
}

 

 


 

 

 FEATURED ARTICLES

Developing a Controller Using Design Patterns - How to apply design patterns during the development of a garage door controller.

Embedded Case Studies by SSI Wireless:

Wireless Integration of Tank Monitoring System to Measure Liquid Levels

GUI for Wireless Automated Guided Vehicles (AGV)

 
 EMBEDDED SYSTEMS NEWSLETTERS
The Real Time Review brings you the latest embedded software news and technical articles - published approx. six times throughout the year.
> VIEW ALL NEWS

RSS Feed