Chapter 9. The Journey

The idea of a journey is all very Zen, but we feel that it describes the fact that most engineers view self-improvement as a large motivational factor. The overall destination may be to build the perfect software and to be loved and admired by our peers. Along the way we have smaller destinations—finish a project, learn a new software tool, improve our productivity, and reduce stress levels. We also like the idea of having fellow travelers. Another important consideration we would like to emphasize is that we are still on our journey, and “perfect” is a very elusive destination, so any help from our fellow travelers would be greatly appreciated.

A project is like a journey as well; some projects can be akin to traveling uphill in mud! Successful projects have a clear destination, a carefully planned route, a map, a compass, and recognizable milestones along the way. Unsuccessful projects have no destination, an unclear destination, or a destination that moves faster than you do. Unsuccessful projects also have inadequate and inaccurate directions or, in the worst case, no directions at all.

This chapter will put meat on the bones of the previous chapters by applying what we've been discussing to an example project. We'll take our project from the very start and discuss along the way the common issues encountered. We'll demonstrate how to apply the techniques discussed in the preceding chapters. Along the way we'll highlight the areas where projects often go bad and discuss why. The demonstration software used in this chapter could be used as a pattern for your own project. We've certainly used it for ours.

Most projects start with an inquiry and an initial meeting to discuss your customers' requirements. Even if you are working internally within a company it doesn't exclude you from having customers such as your manager or the end user, for example.

Agreeing on the Destination (Requirements)

First, get down to basics by listening to what your customer wants and then telling the customer what to expect. Each party understands exactly what the other party is talking about.

To get the ball rolling then, listen to what your customer wants. Right from the start the project can take a wrong turn, your customer could call you and you could do everything over the phone. Following is a list of ways you could undermine your project's chances of success at an early stage:

Agreeing on the Destination (Requirements)

The customer should have an idea about the destination, and before setting out you should be able to confirm with the customer at least the general direction. So, if you're lucky there will be a requirements specification. Here's an example.

This document is usually accompanied by an initial requirements meeting. If no requirements document is made available prior to this, one should be discussed and produced from this meeting.

Now Derek has got to awake from his slumber and respond to the question from Millicent. He has various options; here are a few:

  1. Millicent:

    Yeah, LabVIEW can cope with anything you throw at it.

    The problem here is that a bluff nearly always gets overtaken by reality. The other problem is that you are giving the customer the go-ahead to make changes without any consideration. Go this way, and you'll end up having end of project blues.

  2. Millicent:

    We will need a complete specification before we can begin. Changes later on are far too expensive to rectify and will weaken the design of the software.

    For languages like C or Pascal this is a reasonably valid path to follow, because if using these languages, the developer will disappear for three months and reappear with a finished product. This can be a recipe for customer disappointment if the requirements are not concisely and accurately defined and understood by all concerned parties. LabVIEW gives the advantage of Rapid Prototyping, use it!

    You also have to consider that the only constant in software projects is change. As your customers learn more about the system they will have more suggestions and comments. It's a fact of life and we all have to cope with it. A large amount of work will pass you by with this attitude because in business customers don't want to wait.

    Finally, a decent language combined with a robust design strategy will allow flexibility at a reasonable cost.

  3. Millicent:

    LabVIEW is the language for writing the application, and the design of the application can be flexible or not. This depends on the effort put into the design and the inherent complexity of the system. We should design the system with flexibility in mind, but obviously there will be a cost consideration for large system changes. As long as the basic requirements stay the same we can reevaluate the process at each milestone.

We will also need to ensure that changes in requirements are communicated in an efficient manner and that only one person in your organization communicates them to us.

Go for it Developer man!

Anyway, we've chosen option 3 and the meeting continues.

The next step after the requirements have been communicated, is for you to tell what the customer is going to receive. This could be in the quote, contract, or as we like to call it, the target specification, and it should be regarded as your promise to the customer.

This is a communication-intensive process, so be prepared to talk to your customer. For example, it's a rare event when you get a requirement specification with no gaps in it. In this case there is little mention of the data to be collected by the system. Call them and clarify before you quote!

Accompanying the target specification should be the test plan. This will be the instrument for confirming that the destination has been reached.

Finally, we suggest the use of a prototype to better elicit requirements. However, this is usually only realistic at the requirements stage if the project has a separate cost feasibility stage. Alternatively, this can also be done as part of the design process to fine-tune the requirements. For your own sanity be prepared. Even if your software eradicates poverty from the world there will be someone who complains about the font!

Without a target specification your customer will not have confidence in what he or she is getting, and without a test plan the project will have no closure. You know what you are producing and your customer knows what he or she wants. A project will only be successful if everyone agrees.

So to summarize, the target specification should describe the key functionality of the system, and the test plan should list the tests that will establish that this functionality has been met.

In our journey these documents are the backpack, walking boots, food, compass, and map.

Planning Your Route (Design)

Code and Fix

Code and Fix

NO NO NO NO NO NO NO NO NO NO NO NO!

This is like embarking on a journey armed with unclear directions, no map or compass, and a vague idea of your destination.

We don't suggest you go down this road, since death and pestilence will be your traveling companions.

Abstracting Components from Requirements

Abstracting Components from Requirements

Noun Parse of Requirements Specification

Noun

Noun

Widget

Analog Output port

Widgetometer

Visual Inspection

Test system

Calibration

Test specification

Test position

Display (Widgetometer)

Active test position

Output Port (Widgetometer)

Customer test specification

RS232 Communications

Part number

Standard Widget

Data

Test ports

Printout

Reading

UUT

Communication port

 

Noun Parse of Target Specification

Noun

Noun

Main Display

Part number

Central Display Area

Time of Test

Control Buttons

Issue

Dialog

Software Version

Units Under Test

An Out

Test Type

Serial Out

Unit Details

Display Out

Serial Ports

File

Test Report

Directory Structure

User Name

 

Date of Test

 

Serial Number

 

There are a few hidden components that most systems will need. For example, for this ATE there is no mention of the display and how it should look. A phone call confirms that the customer would like to see the test status and unit details on a screen.

We can also have a look at the hardware design to swipe a few ready-made components. For example, there is a digital multimeter (DMM) for taking the measurements, a Switching System for making the connections, and a PSU (power supply unit) for providing power. Now you can try to disregard repeats and obvious components that are outside the system.

So, let's go through our list and collate what we have identified into a smaller set of nouns, deleting those that we don't need:

Nouns

 

Widget

 

Widgetometer

Discard—is not meaningful for ATE

Test system

 

Test specification

Discard—not part of system

Display (Widgetometer)

Put in Hardware

Output Port(Widgetometer)

 

RS232 Communications

 

Standard Widget

 

Test ports

 

Reading

 

Communication port

 

Analog Output port

 

Visual Inspection

 

Calibration

 

Test position

 

Active test position

Discard—replace with Test Position

Customer test specification

Discard—not part of system

Part number

 

Data

 

Printout

 

UUT

 

Main Display

Replace with Display

Central Display Area

Replace with Display

Control Buttons

Replace with Display

Dialog

Replace with Display

Units Under Test

 

Test Type

 

Unit Details

 

Serial Ports

 

Test Report

 

User Name

 

Date of Test

 

Serial Number

 

Part number

 

Time of Test

 

Issue

Discard—relates to documentation

Software Version

 

An Out

Discard—same as Analog Output Port

Serial Out

Discard—same as RS232

Display Out

Discard—same as Widgetometer display

File

 

Directory Structure

 

From our table we can see that some nouns have been discarded, but others have been replaced with (we think) a more meaningful description—Display.

Customer test specification and test specification are obviously referring to the same thing, so drop customer test specification because the system will not care who owns the specs.

There's also an argument that test position and active test position are similar enough to be ignored. Active could be an attribute of test position perhaps.

All right, our next job is to group the nouns under a heading.

Data

Hardware

Test System

Report

Display

Test Report

Widget

Visual Inspection

Printout

Display

User Name

Output Port

Calibration

 

Control Buttons

 

(Widgetometer)

   

Date of Test

RS232 Communications

Test position

 

Dialog

Serial Number

Standard Widget

Part number

  

Part number

Test ports

UUT

  

Time of Test

Reading

Units Under Test

  

File

Communication port

Test Type

  

Directory Structure

Analog Output port

Unit Details

  

Software Version

Test position

Serial Ports

  
 

Widgetometer display

   

We have grouped each of our nouns under a heading that collectively describes it. This should be our starting point for the highest level components. More than one design can solve a problem, and you could have dissected the nouns differently and still come up with a decent design. For our example though, we have decided that our table headings now represent the main components in our system.

Putting it all together we will have a display that is populated by readings taken from the test system component. This test system will consist of a hardware component that will model all the states of the hardware. The hardware component will be responsible for talking to the serial communications, the DMM, and the visual inspection system. The results will be stored by a data component and printed by the report component. The component interaction diagram will look like Figure 9.2.

Widgetometer top-level component interaction diagram.

Figure 9.2. Widgetometer top-level component interaction diagram.

Now at the top level we can define the actions for each component.

Display Handler

This component describes the abstract things that the display will be required to do.

  • Reset Display

  • Show Test Position

  • Update Test Position

  • Update Status Area

Test System

This will be a state machine that will run through each test for each unit, checking pass-fail criteria and distributing the results data. So as well as the individual tests there will be states that model initialization, storing data, checking status, error states, and printing reports.

Hardware Component

Any individual action for the hardware is modeled by this component. This is at the highest level of abstraction.

  • Initialize

  • Measure UUT Channel 1 An Out

  • Measure UUT Channel 2 An Out

  • Read UUT Channel 1 Serial

  • Read UUT Channel 2 Serial

  • Read UUT Data Serial (this is Serial Number, Part Number, etc.)

  • Get UUT Channel 1 Display

  • Get UUT Channel 2 Display

Report Component

Any output to any printer is handled by this component. At this stage there is only one report required.

  • Initialize

  • Print Report

Data Component

All test data is held here. This component has the responsibility for loading test limits and settings as well as storing and archiving the test results.

Command

Attribute

Initialize

Measure Error %

Load Test Settings and Limits

Read Error %

Store Test Results

Display Error %

Get Limit

Measured Value 1 (An out)

Set Result

Measured Value 2 (An out)

 

Read Value 1 (Serial)

 

Read Value 2 (Serial)

 

Read Value 1 (Display)

 

Read Value 2 (Display)

Configuration Component

This component handles anything to do with the configuration data. The attributes will be set during development.

  • Load All

  • Save All

  • Load

  • Save

  • Get

  • Set

Initialization

This component sets up the configuration data and anything else that needs initializing.

At this stage the top-level components are doing very broad, abstract operations. The language of the commands is very specific to the test system. The components that these top-level components employ will become more and more specialized the farther down the program hierarchy they are.

Okay, this is a bit contrived, and since design is a gray area there will be other ways of doing it. Practice has shown us that using these techniques does throw up similar designs again and again. Patterns are a way of taking advantage of these prefabricated designs.

Using Patterns to Help the Design Process

Using Patterns to Help the Design Process

UI

There are two design patterns that we can employ here. If it looks as though the system is going to have a lot of individual displays, then we suggest starting off with the Menu Tree Pattern. If any of the displays are complex and require information from subVIs to be passed and displayed, we suggest using the UI Controller>>Message Queue Pattern for each.

This system doesn't require a large number of displays and therefore doesn't merit a menu-submenu system, but the complexity of the data to be displayed on the main UI does warrant the use of the UI Controller>>Message Queue Pattern.

First, let's reach a consensus about what the general UI operation is going to be.

A meeting is called with the main protagonists attending:

There has been a lot of information floating about, so Derek now writes the following on his sketch.

UI States

Initialize>>Set Up Display>>Run>>Finish

These are fairly repeatable from system to system. The other common state for the system could be a general error state where the program goes if it all goes horribly wrong.

Action

Description

No Action

Just ignore

Disable Position

Disables the selected position

Enable Position

Enables the selected position

Position Visible

Makes the selected position visible

Position Invisible

Makes the selected position invisible

Update Position Data

Updates the data for the selected position

Update Instruction Display

Sends text to the Instruction display

Set to Tests Not Started

Sets the display to the not started state

The beauty of separating the actions like this is that you can design the basics of the system and implement them for the prototype without getting bogged down in detail. You know that the User Interface will react to the commands even though the actual contents of the Unit Data areas have not been established yet.

UI Attributes

Position Number (1 . . . 5)

This is a useful technique for simplifying the interface. Derek could have described the system fully by having lots of UI actions. For example, he could have had Disable Position 1, Disable Position 2, . . . Disable Position X. There is a potential problem in that the customer could come back and say that for cost purposes he or she wants to test 10 units. While not a showstopper, it could become cumbersome to have to write in all the commands for each unit.

Program Executive States

Test Not Started>>Enter Data>>Testing>>Tests Complete

There will also be a Test Executive defined as part of the Testing State. We'll come back to this when we have the Test Specification of the Widgetometer.

We now have an idea of the User Interface, so let's tackle the hardware.

Back to the meeting.

Hardware Actions

  • UnderRange

  • Read Unit Status

  • Read Unit Serial Number

  • Read Unit Part Number

  • Read Unit Software Version

  • Read Chan1 Reading

  • Read Chan2 Reading

  • Get Chan1 An Out

  • Get Chan2 An Out

  • Get Chan1 Display Reading

  • Get Chan2 Display Reading

  • OverRange

The Hardware component actions are now defined and there is a list of jobs that need doing. Using the Control >>Drive>> Read Pattern we can break down the components further (although this is not necessary for the purpose of the meeting).

Hardware Attributes

  • Unit Number (1 . . . 5)

Some customers haven't thought that deeply about what they want. It is also often the case that they don't fully understand what they want until they get it. This happens frequently, so we recommend the use of a prototype to demonstrate the User Interface interactions.

Building the Prototype

In LabVIEW, building a prototype is not necessarily expensive, and if you use patterns you can use the prototype as the basis for your main program. The idea of a prototype is to emulate the look and feel of how you envision the program working. Therefore, the User Interface should be functional to the extent that buttons can be pressed and data displayed. There shouldn't be any connections to the hardware at this stage. You shouldn't spend much more than one to two days putting the prototype together.

Another small bit of advice given to us by an ISO9000 auditor is “always feed them something,” by this we mean deliberately leave something out or leave an obvious gap. In the auditor's case it was a ploy used by those being audited to distract. In our case we can use it to generate customer involvement, or to get customer “buy in” and start the conversion. We have found that people begin to accept the design more readily if they feel that they have contributed to it in some way. We should try to animate each step in the program—remember it is a demonstrator for the customer.

  1. —Transfer of User Interface Pattern

    Download and extract the examples from the Website. Copy the “UI Controller-Message Queue Pattern” directory in its entirety to a new directory called “C:WidgetometerSoftware.” In the directory, Widgetometer Test SystemSoftware1 Displays1 Main Display, change the name of the User Interface.vi to Widgetometer User Interface.vi. It is also a good time to change the Window Title for this VI.

  2. —Design your User Interface

    Dump all the controls and indicators onto the Front Panel and tidy up, as shown in Figure 9.3.

    Prototype screen.

    Figure 9.3. Prototype screen.

From the requirements document it was established that there would be five test positions. This was the limit of what could be displayed completely on the screen, without having to resort to summary screens. A Strict Type Def. cluster was created that held all the data for each unit under test. Copies of this cluster were distributed around the screen and titled Position 1–Position 5. Using a Strict Type Def. cluster will allow you to make changes to all of the clusters at the same time. The central area was allocated for instructions and test details and is just a plain string. Finally, the [Exit] button was left as is and [Button2] was renamed [Start Test].

Before we go on to actually emulating the running of the test, let's look at what basic actions we require from the User Interface.

User Interface Basic Actions

  • Each position cluster will need to be updated, enabled, disabled, and made visible or invisible.

  • For every [Start Test] button there should be a [Stop Test] button.

  • The [Exit] button should be disabled during a test.

  • [Button3] should be made invisible, since there is no apparent use for it yet.

Following are the User Interface Actions that came with the pattern:

Action

Description

Underrange

Throws or passes error

Clear Queue

Clears the queue of display actions

Get Display

Gets the next display item off the queue

Enable Button 1

as action

Disable Button 1

as action

Enable Button 2

as action

Disable Button 2

as action

Button 2 Visible

as action

Button 2 Invisible

as action

Enable Button 3

as action

Disable Button 3

as action

Overrange

as Underrange

Button 1 is the [Exit] button for our User Interface and the action should be updated to reflect this. Button 2 is the Start/Stop Test Button and, as well as renaming the button, we need further action to change the button text. Button 3 needs the visible-invisible actions.

We need to list new actions for the position clusters—these will be update, enable, disable, visible, and invisible. We should leave the UnderRange, OverRange, Get Display, and Clear Queue actions alone since they are always used.

The new User Interface Actions will need to be put into the Display Command.ctl and the Display Setting.ctl. Just open, edit, and save each control.

Prototype screen.

Display Command.ctl

Display Setting.ctl

Underrange Error

No Display

Clear Queue

Enable Exit Button

Get Display

Disable Exit Button

Enable Exit Button

Enable Start Stop Button

Disable Exit Button

Disable Start Stop Button

Enable Start Stop Button

Update Start Stop Button Label

Disable Start Stop Button

Enable Button 3

Update Start Stop Button Label

Disable Button 3

Enable Button 3

Button 3 Visible

Disable Button 3

Button 3 Invisible

Button 3 Visible

Enable Position

Button 3 Invisible

Disable Position

Enable Position

Position Visible

Disable Position

Position Invisible

Position Visible

Update Position

Position Invisible

Update Inst Screen

Update Position

 

Update Inst Screen

 

Overrange

 

Create a Strict Type Def. enumerated control that models the test position, and its values should be:

  • Underrange, Unit 1, Unit 2, Unit 3, Unit 4, Unit 5, Overrange

Save it as Test Position.ctl and use it everywhere.

The UI queue component will have the Test Position.ctl as both input and output, and it will also pass it as part of the message queue. The adjustments to the UI queue component are relatively straightforward.

  1. Open the UI Queue.vi.

  2. Select the Test Position control using the “Select a Control . . .” button on the Control Palette.

  3. Drop it into the Input box and copy it to the Output box.

  4. Change the Test Position.ctl in the output box to an indicator.

  5. Copy and Paste the Test Position control into one of the Local Store Clusters. This is a Strict Type Def. and will need to be opened and the Test Position control pasted into it.

  6. Wire the input and output connector terminals.

  7. Finally, wire the input and output controls onto the block diagram.

The result should be something like Figure 9.4.

UI queue component panel and connector.

Figure 9.4. UI queue component panel and connector.

The cluster constants seen in the diagram in Figure 9.5 are instances of the Strict Type Def Queue Items.ctl, and any changes to it are reflected in changes to the diagram.

UI queue component diagram.

Figure 9.5. UI queue component diagram.

Figure 9.6 shows the UI controller component that acts as a wrapper for the UI queue component. Once again we'll need to add the Test Position.ctl as both input and output and wire them to the connector. If you open up the diagram, you'll notice that the source has changed to reflect the new values for the instances of Display Setting.ctl and Display Command.ctl. Spooky!

UI controller component panel and connector.

Figure 9.6. UI controller component panel and connector.

The Test Position.ctl will need wiring into and out of the case structure and connecting to the UI queue component where required. In this case it is only required as an output from the Get Display>>More Items?=True case. See Figure 9.7 for the wiring diagrams.

UI controller component diagrams.

Figure 9.7. UI controller component diagrams.

Now we need to add the new cases to correspond to the elements in Display Command.ctl. This is a simple matter of selecting a suitable case and right-clicking and selecting Duplicate Case from the pop-up menu as shown in Figure 9.8.

Duplicating a case.

Figure 9.8. Duplicating a case.

The new case will automatically take on the name of the next element in Display Command.ctl, which in this case is “Enable Position.” This case needs to be aware of the test position, so it will need Test Position wiring into the UI queue component. See Figure 9.9 for wiring of additional cases.

Additional cases for UI controller.

Figure 9.9. Additional cases for UI controller.

Finally, we need to make each action work! Look at the Control Display While Loop on the Widgetometer Test System block diagram in Figure 9.10. Right-click on the case structure and select Add Case for Every Value. Now you have a set of pigeonholes awaiting their actions. All of these actions are simple attribute settings, except for Update Position, and we'll tackle that later.

Control Display While Loop.

Figure 9.10. Control Display While Loop.

Here's the code for the Control Display While Loop as shown in Figure 9.10.

Figure 9.11 shows examples of the cases filled out. You will need a case for every action.

Control Display cases.

Figure 9.11. Control Display cases.

Now if you load a Test Stub VI called UI Display Stub.vi, and run the Widgetometer User Interface, you will be able to test the changes that have been made. The UI Display Stub.vi simply places messages on the message queue, and these are actioned by the User Interface. Now we are ready to give the prototype some life.

On starting, the program will settle into its first state: Test Not Started. When the start button is pressed, the Enter Data state is activated. After successfully entering data, the Testing state is started and the sequence of tests are run through. When the tests are done, the Tests Complete state is entered and any posttest actions finished.

A flexible approach is to produce a simple component that drives the program executive states. Figure 9.12 demonstrates how.

Program Executive State Controller.

Figure 9.12. Program Executive State Controller.

Program Executive State Controller.

This component stores the required program executive state locally, by the “Set Test State” command, and returns it once on a “Get Test State” command. All we need to do now is have a loop checking the Test State and acting when it changes, and we have ourselves a nice, flexible program executive. We'll add the loop to the Widgetometer User Interface VI and put in some functionality, or the “Enter Data State.” A simple Enter Data dialog box was created, and if you notice the Monitor Control Buttons loop on the diagram in Figure 9.13, you'll be able to see that when button 2 [Start Stop Test] is pressed, the Test State is set to Enter Data. When the Program Executive loop next iterates, it will retrieve that state and action it.

Program Executive Enter Data State.

Figure 9.13. Program Executive Enter Data State.

Inside the Enter Data dialog will be the code that decides what step to go to when the dialog exits. If it exits on a Cancel the next state should be to return to Test Not Started. If the dialog exits successfully then the next state would be Testing. In a similar fashion to decoupling the User Interface actions from the front panel, we've now decoupled the Program Executive actions. We now have the freedom to control the way the Test Sequence runs from nearly anywhere in the software hierarchy.

Build

Now we can proceed on our journey with the confidence that we have done everything possible to extract information from our customer. The customer in turn should have some confidence that the project about to be received will make him or her truly thankful.

So, onward.

Code and Fix

Code and Fix

LCOD

LCOD

Hardware

Looking closer at the hardware pattern, we've already defined the top-level commands for the component, so now we'll go deeper. Each hardware action is a combination of Control, Drive, and Read. There may be no need for all of them, but at least one will be required. For instance, a simple thermometer would only have the Read component, whereas a scanning thermometer would have a combination of Control and Read.

Here's the implementation for this project and a reminder of the actions for this component.

Hardware Actions

It transpires that the power is switched on to all the units at the start of the test and removed at the conclusion of testing. This means that two extra hardware actions are required to apply and remove power to the units.

So, here are highlights from the source code.

Action

Description

UnderRange

Throws or passes error

Initialize System

Sets up all the hardware components

Switch STDs In

Connects the standard units to the selected test position

Reset Switches

Clear connections

Read Unit Status

Read the selected unit's Status from the serial port

Read Unit Serial Number

Read the selected unit's Serial Number from the serial port

Read Unit Part Number

Read the selected unit's Part Number from the serial port

Read Unit Software Version

Read the selected unit's Software Version from the serial port

Read Chan1 Reading

Read the selected unit's reading for channel 1 from the serial port

Read Chan2 Reading

Read the selected unit's reading for channel 2 from the serial port

Get Chan1 An Out

Measure the selected unit's channel 1 analog output

Get Chan2 An Out

Measure the selected unit's channel 2 analog output

Get Chan1 Display Reading

Get the display reading for channel 1

Get Chan2 Display Reading

Get the display reading for channel 2

Power On

Apply power supply to units under test

Power Off

Remove power supply from units under test

OverRange

As UnderRange

Looking at Figure 9.14 you can see that Test Position is a Strict Type Def. enumerated type that has already been defined for the prototype and is used throughout the software. Hardware Actions is a new Strict Type Def. enumerated type that has all the actions that were defined earlier.

Hardware component front panel.

Figure 9.14. Hardware component front panel.

Hardware Actions has been set to “required” as a precondition, and a standard wiring pattern has been defined, as shown in Figure 9.15 and 9.16. All components will follow this pattern where possible.

Widgetometer hardware icon.

Figure 9.15. Widgetometer hardware icon.

Standard wiring pattern.

Figure 9.16. Standard wiring pattern.

The block diagram looks like that shown in Figures 9.17. The first time through the hardware is initialized.

Hardware component block diagram.

Figure 9.17. Hardware component block diagram.

The UI screen control is sent a message describing each action that has been taken by the hardware component. The hardware action is then implemented. The actions that talk to the serial ports are all pretty repetitive and involve sending the message and the unit position for that message to the read component. This will then do all the communicating and return a string or numeric value. The measure action is a bit more involved; it requires a bit of switching to select the unit under test.

Clearly demonstrated here is the self-documenting nature of LCOD—you can see exactly what each component is being asked to do.

Programming the Get Chan2 An Out action was simply a matter of duplicating the Get Chan1 An Out case and changing the command to the control component as shown in Figure 9.18. The Power On and Power Off commands use the drive component and simply set the power supply volts to 24 or 0 as shown in Figure 9.19.

Get Chan 1,2 An Out.

Figure 9.18. Get Chan 1,2 An Out.

Power On/Off.

Figure 9.19. Power On/Off.

The hierarchy in Figure 9.20 shows the Control>>Drive>>Read pattern. Below the generic Switch, DMM, and PSU components would be the manufacturers or your own drivers. For continuity we tend to rewrite them as components as well.

Widgetometer Control Drive Read pattern.

Figure 9.20. Widgetometer Control Drive Read pattern.

Control Actions

It is envisioned that the measurement and signal lines are switched from the units under test to the computer and measurement equipment.

Action

Description

UnderRange

Throws or passes error

Init Control System

This initializes the control hardware, getting and setting identifiers and setting initial conditions

Reset Switches

Set all switches open

Switch Standards In

Switches the standards into the chosen position

Switch DMM to Chan1

Switches the DMM to channel 1 of the chosen position

Switch DMM to Chan2

Switches the DMM to channel 2 of the chosen position

OverRange

As UnderRange

Here's the implementation.

So regarding Figure 9.21 we will define Control Commands as a Strict Type Def. enumerated type and use Test Position as in the hardware component.

Control component front panel.

Figure 9.21. Control component front panel.

As we go to lower levels of abstraction we can see the commands becoming more oriented to the hardware. This is demonstrated by the states in Figures 9.22 and 9.23 that are now less identifiable as part of a test system and more specific to switching systems.

Control Component Initialize State.

Figure 9.22. Control Component Initialize State.

Control component switching commands.

Figure 9.23. Control component switching commands.

Drive Actions

Drive is used for signal injection, PSU setting, and similar actions. For this project there is a requirement to switch on the power supply to the Widgetometer.

Action

Description

UnderRange

Throws or passes error

Init Drive System

This initializes the drive hardware

Set PSU Volts

Sets the power supply volts current

Get PSU Volts

Returns the power supply volts

Get PSU Current

Returns the power supply

Clear PSU

Sets the power supply to a safe level, 0 Vdc

OverRange

As UnderRange

The front panel, as shown in Figure 9.24, is a command Strict Type Def. enumerated type, with just the voltages in and results out.

Drive component front panel.

Figure 9.24. Drive component front panel.

The rest of the states are the same, as shown in Figure 9.25, with corresponding messages to the PSU component.

Initialize drive component.

Figure 9.25. Initialize drive component.

Read Actions

There will be a multimeter for analog input measurement. There will also be the commands to talk to the serial port. Finally, we'll put the visual inspection stuff in here as well.

Action

Description

UnderRange

Throws or passes error

Initialize Meas System

This initializes the measurement hardware

Read Unit Status

Read the selected unit's Status from the serial port

Read Unit Serial Number

Read the selected unit's Serial Number from the serial port

Read Unit Part Number

Read the selected unit's Part Number from the serial port

Read Unit Software Version

Read the selected unit's Software Version from the serial port

Read Chan1 Reading

Read the selected unit's channel 1 reading from the serial port

Read Chan2 Reading

Read the selected unit's channel 2 reading from the serial port

Get Chan1 Display Reading

Get the display reading for channel 1

Get Chan2 Display Reading

Get the display reading for channel 2

Measure Analog Out

Returns the dc volts from the DMM

OverRange

As UnderRange

Let's quickly look at some of the implementation of these actions.

Figure 9.26 shows the Read component front panel, where once again we use the ubiquitous Test Position Strict Type Def. enumerated type, and as before we define a new Read Commands Strict Type Def. enumerated type with the commands defined earlier.

Read component front panel.

Figure 9.26. Read component front panel.

Nothing too tricky about this. The read component merely calls the visual, serial, or DMM components and returns their responses as shown in Figures 9.27 and 9.28.

Visual component call.

Figure 9.27. Visual component call.

DMM and serial component calls.

Figure 9.28. DMM and serial component calls.

The only other action of note is the Initialize command, which is shown in Figure 9.29.

Read Initialize action.

Figure 9.29. Read Initialize action.

Finally, you need a test executive, so that is discussed next.

The array of hardware actions drives the For Loop for each active test position. In reality, the results would go to a file or a database. The more observant reader will have looked at Figure 9.30 and noticed that the array “Tests” is an array of constants. Correct! Although they are dynamic Strict Type Defs., they are indeed constants and would be better placed in a file.

Widgetometer test executive.

Figure 9.30. Widgetometer test executive.

Detail Outside the Code

If you see a constant String or Number anywhere in your code, pull it out into a configuration file. We use a pattern for this that takes advantage of the flexibility of enumerated types.

Make a copy of the Prototype Software Directory on your hard drive and rename it Widgetometer Software Directory. Now you need to copy the configuration directories over to where the program resides. So copy the following directories to your Widgetometer Software Directory:

  • ....PatternsSection Keyed Data Handling Pattern1 Displays

  • ....PatternsSection Keyed Data Handling Pattern2 System

If this has been done correctly, you will find that the following message will be displayed as shown in Figure 9.31.

Confirm Folder Replace.

Figure 9.31. Confirm Folder Replace.

Select [Yes to All].

Rename the directories to suit as shown in Figure 9.32.

Rename directories.

Figure 9.32. Rename directories.

Open Widgetometer User Interface.vi and find any lost VIs. Widgetometer User Interface loses Widgetometer Enter Data.vi and 2 button dialog.vi. Then select File>>Save With Options>>changed VIs from the menu and save everything.

Without closing Widgetometer User Interface.vi, open Config ini.vi and as before find any lost VIs or Controls. This is usually just Datamanager.ctl. Once again select File>>Save With Options>>changed VIs from the menu.

Rename Config ini.vi to Widgetometer Config ini.vi, and update the icon to reflect the new program.

Now we need to open the configuration file when the program starts and load all the configuration data. In Widgetometer User Interface.vi you will find UI Initialize.vi, open it up and put . . .\2 System2 Data Handling1 File Management1 File HandlerFile Handler.vi into it, and put in the file path to the configuration file as shown in Figure 9.33.

Add configuration to initialize VI.

Figure 9.33. Add configuration to initialize VI.

Also put in the two data manager VIs. They can be found in . . .\2 System2 Data HandlingConfig Data (or copied from the hierarchy diagram). Pop up on the command input and select “Load All”.

Now drop Widgetometer Config.ini into the case for Button 3 in Widgetometer User Interface.vi diagram (run state), as illustrated in Figure 9.34.

Make Config.ini dialog active.

Figure 9.34. Make Config.ini dialog active.

You can optionally change the names of the data manager files and customize the icons to your individual requirements. What you now have is the capability to create, load, and save constants in a reasonably secure location. Defining these constants is as simple as updating an enumerated type control.

Let's do a couple as an example. Let's remove the example parameters and add a new parameter called System Name. We've changed the data manager names to Widgetometer System Config Data Man.vi and Widgetometer System Config Data Man2.vi.

Double-click on the parameter control on Widgetometer System Config Data Man.vi front panel to bring up the control editor (if you haven't got this option set you'll have to open the control in longhand by highlighting the control and selecting customize from the menus). Figure 9.35 shows the resulting screen.

Customize parameter.

Figure 9.35. Customize parameter.

Remove the example parameters and replace the last one (you won't be able to remove it) with System Name.

To run the new set up you will have to ensure that the directory for the Config.ini file exists (as pointed to in UI Initialize.vi). The ini file will be automatically created when the program is first run.

Now run Widgetometer User Interface.vi and select Button 3 (after it moans about there being no file). The Config.ini dialog should be displayed. You will notice that there is now a key called System Name.

Other constants we could pull out of the code at this stage are:

  • Power Supply On Volts

  • Power Supply Off Volts

  • Serial Port Settings (baud rate, handshaking protocols and data, and start and stop bit sizes)

All you do then is drop the Widgetometer System Config Data Man.vi into the relevant hardware VI and wire it as shown in Figure 9.36.

Taking detail out of hardware VI.

Figure 9.36. Taking detail out of hardware VI.

Finally, the array of Strict Type Def. enumerated types used to drive the Test Executive should also be generated from the configuration file.

Error Handling

In keeping with the components within components theme we have created an error handling component. This component can be set to a mode where it complains loudly (throws dialogs) or logs errors discretely. In development mode you want it to complain loudly, and in run mode you want it to store the errors in a file. This component is called Error Control.vi and comes with both the User Interface Pattern and the Config.ini pattern.

Information hiding makes the error handling decision-making process a little simpler. Lower-level private components can pass errors up to their peer components. These errors can then be handled by the top-level components. The following diagram, as shown in Figure 9.37, illustrates the process.

Widgetometer hardware error handling.

Figure 9.37. Widgetometer hardware error handling.

The program executive could also have an error state that handles the errors and warnings in an elegant manner.

State Machines

The program executive was discussed earlier, but what are the advantages of doing it like this? It is actually quite easy to list the different states of a system. From a hardware perspective, most test systems have very few states. These states are then defined by the hardware component. So using state machines has simplified the definition of the problem.

The program executive is usually just as simple to define. The ones in Figure 9.38 describe a common pattern.

Widgetometer program executive.

Figure 9.38. Widgetometer program executive.

Another common state machine is the Test Executive. The one used in this system takes advantage of the fact that the hardware component models all the states that the test system has. It takes an array of these states and sticks them into a For Loop, creating a sequence of states that defines the test. For extra flexibility this array of constants should be pulled out of the code and stored in a file.

The state machine structure also helps when changing code. In the Widgetometer case if we wanted to define and add a completely new test, we would simply update the hardware component and add the new hardware actions to the array in the Widgetometer test executive.

Reuse

What have we reused and how much effort has it saved us?

Patterns

Patterns allow us to reuse design and also enable us to reuse more of our code.

For this project the following patterns were used:

  • UI Controller-Message Queue Pattern

  • Section Keyed Data Handling Pattern

  • Control>> Drive>>Read Pattern

VIs With Little or No Modification

It's all right, we're not going to list them all. A quick count tells us that without including any of the hardware, we have reused nearly 70% of the code in some shape or form.

Reuse can sometimes have implications on the design, since you can end up changing your design so that you can reuse existing code. This shouldn't be the case with LCOD because the patterns are purely a way of emulating the patterns observed in all systems when you start using components in your code. Strict Type Defs. then allow you to modify the pattern to suit your design.

Also, what new code can you reuse in future systems? For a start, you can pluck out the lower-level hardware VIs.

Style

If you are in a multideveloper environment you will find the following checklists useful for broadcasting the standards expected for a job. They are also quite good as reminders, even if you're working on your own. We like checklists!

Uh-oh We've Been Given the Wrong Directions

On rare occasions (like every project we've ever worked on!) the customer changes his or her mind, or wants extra functionality. This happens because the customer doesn't fully comprehend the system until seeing it and using it. This will result in a change in requirements. You can regard this as either an opportunity to shine or an opportunity to have a cardiac arrest.

The customer doesn't like the concept of entering data by dialog boxes, so he or she has decided to automate the test by reading the BCD inputs to the LCDs, provided by a test port. There are four digits of four bits for each card. With some digital multiplexing we can switch between displays on the unit under test and then between units. This can be done with a cheap Digital I/O card and a little bit of circuitry.

Port 1 Bits 1–4

- Digit 1 (least significant digit)

Port 1 Bits 5–8

- Digit 2

Port 2 Bits 1–4

- Digit 3

Port 2 Bits 5–8

- Digit 4 (most significant digit)

Port 3 Bit 1

- Display 1 & 2 Switch

Port 3 Bits 2–5

- Unit Selector

What do we have to change and where? Well, we know that all the tests are in the hardware component, so we can start there. Note how strong cohesion cuts down on all the hunting around for affected VIs.

So, at the hardware component we don't need to change the commands, and the public interface remains the same. As far as any VIs are concerned nothing has changed.

The actions affected are:

  • Get Chan1 Display Reading

  • Get Chan2 Display Reading

The changes are shown in Figures 9.39 and 9.40.

Hardware before changes.

Figure 9.39. Hardware before changes.

Hardware after changes.

Figure 9.40. Hardware after changes.

Three new actions have been added to the control component to set the display to be read (1 or 2), and to switch in the digital multiplexer for the required test position. We've also improved the read component slightly by combining the “Get Display Reading” commands into one generic command.

Figure 9.41 shows the new control component additions.

New control actions.

Figure 9.41. New control actions.

And you'll notice that a new DIO component has been created. Figure 9.42 shows what it looks like inside.

DIO component.

Figure 9.42. DIO component.

The read component changes consist of deleting the “Get Chan2 Display Reading” case and its corresponding command from the Read Commands Strict Type Def., and changing the “Get Chan1 Display Reading” to just “Get Display Reading”.

The visual component is then modified to include the new DIO code for reading the BCD inputs to the displays. These changes are shown in Figure 9.43. For convenience we've committed a bit of naughtiness here; we're going to use the DIO component in the read component as well. Oh well, rules are meant to be broken. We should move the DIO component from its private directory to a public directory though to indicate that it is now being shared.

Visual component.

Figure 9.43. Visual component.

This clearly demonstrates the improved maintainability gained by incorporating information hiding, strong cohesion, and loose coupling. The result is that the robustness of the system has not been compromised by a reasonably sized design change. For the sake of brevity we'll only discuss the impact of the next change.

The customer would like a history of the actions of each test in the sequence displayed on the front panel. What we could do is shrink the current status indicator and add another new indicator called History. If you set the text small and use the Courier font it will look somewhat like a printout.

To implement it you will need to do the following, as shown in Figure 9.44.

New History Display.

Figure 9.44. New History Display.

Add two new commands to the UI controller commands and settings controls: “Clear History” and “Add to History”. You do this by adding the commands to the end of the respective enumerated types. Duplicate the cases in the UI Controller component and implement the new commands.

In the Widgetometer User Interface VI add the new cases to the case structure in the Control Displays loop and put in the string manipulation required. Figure 9.45 shows an example.

Add History Display action.

Figure 9.45. Add History Display action.

You can then either send all calls to the hardware component to this display, or format something nice in the test executive and send that. The test executive option is demonstrated in Figure 9.46.

Update History in test executive.

Figure 9.46. Update History in test executive.

Review Sections 9.2.4 and 6.2 for more information on the ease of updating displays by implementing LCOD message-sending techniques.

Conclusions

So, the conclusion to our journey will be a happy ending. We provide the widget test software and the customer is blown away with the sheer brilliance of our software. We test the application against the test plan and it passes with flying colors. We are heralded as the masters of LabVIEW and a ticker tape parade is held in our honor . . . complete fantasy!

That would make our example project the worst fairy tale of all. Undoubtedly, problems will occur. Our example project could twist and turn with remarkable speed. The problems that could manifest themselves include:

  • The market changes and new functionality has to be added.

  • The people participating in the project change, bringing a whole new set of requirements and perceptions.

  • Problems in third-party software rear their ugly heads and cause havoc with the system performance.

  • The customer realizes that very late into the project, he or she has missed a fundamental test that would render the equipment useless without it.

How do we cope with all the possible problems and unknowns?

Hopefully, everything that we have discussed has shed light on what will give you a decent chance for success. LCOD with basic software engineering practices has enabled us to approach any project armed with the tools that will get the job done. Concentrating on loose coupling and strong cohesion allows the system to be defined simply. Information hiding allows the system to be designed with available information. These simple design strategies have long stood the test of time, and will remain doing so.

We know that using these techniques will help tame the complexity monster that all but the simplest projects can turn into. We know this because we have used them.

The techniques in this book are purely good design practices; they are not the latest “silver bullet.” Everything we have presented is based on our experiences with LabVIEW and commercial projects. The techniques fit well with LabVIEW and data flow programming, and do not involve learning new abstract concepts and paradigms. As we stated very early on, none of the material in this book is new. We are constantly trying new things, keeping what works and discarding what doesn't.

We encourage you to do the same.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.38.142