Outsourcing >

SSI Quality Process Overview Customer Satisfaction Our Engineers Questions to Ask Technical Lab Testimonials Whitepapers
SSI Embedded Systems Trust Facts

Fact: Over 50% of SSI Staff has 8 or More Years Experience

"You can count on the work being done right and on time." ~ SSI Client

Fact: 30% of SSI staff has twelve or more years experience

"The people blended in and became part of the design team."

Fact: Experienced Team Lead manages all projects

"I was impressed with the quality of SSI's work throughout this contract. I appreciated their ability to work with minimal guidance, and minimal design details. And I greatly appreciated their suggestions and alternate design proposals. Their willingness to work overtime when necessary to meet deadlines was greatly appreciated." ~ SSI Client

Fact: All SSI staff is trained on the Quality Development Process

"Work is spectacular. More exceptional than I thought it would be. Sensors work great. They can detect the slightest pressure accurately. It is WAY beyond my expectations." ~ SSI Client

Fact: Long term staff retention rate at SSI is > 95%

Fact: SSI's Internal Software process operates as CMM Level 3

"The experience was a good one" ~ SSI Client

Fact: SSI has been in business 16+ years

"The best thing about working with SSI is that the people genuinely care about the success of the overall project. Typical contractors stop when they have merely met the letter of the contract that they are bound to; where as, SSI is willing to go above and beyond to drive a project to completion and ultimately success." ~ SSI Client

Fact: Over half of SSI Business is from returning clients

"I would use SSI again" ~ SSI Client

Fact: SSI client relationships last several years

"The best thing about working with SSI is that the people genuinely care about the success of the overall project. Typical contractors stop when they have merely met the letter of the contract that they are bound to; where as, SSI is willing to go above and beyond to drive a project to completion and ultimately success." ~ SSI Client

Fact: SSI's Customers report a consistent 4.5 out of 5 rating for satisfaction

"Keep finding people who can get to the root of the issue and resolve it as specified. [Your Engineer] is golden!." ~ SSI Client

Fact: 100% of clients surveyed said they would recommend SSI to others

"SSI will deliver what is promised on a timely basis." ~ SSI Client

Fact: SSI Supports Continual Employee Training

"Consistent high quality engineers who perform very well. SSI is the only company -- contracting or consulting -- who consistently provides the best talent who are not only technically accomplished but have excellent verbal and personal skills. I have not seen anything like it before." ~ SSI Client

SSI Embedded Trust Facts

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 );
    }
}

 

 

SUBSCRIBE TO NEWS & EVENTS
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
A Certified Women's Business Enterprise and Member of the Illinois Technology Association