PROTOTYPING AND PROGRAMMING DATABASE SYSTEMS

Program development when time is important

Miles Dempsey

Miles is vice president of ProtoView Professional Services, the consulting arm of ProtoView Development Corp. He can be contacted at 5920 Roswell Road, Suite B107-221, Atlanta, GA 30328; 800-572-0988.


Imagine that it's 20 degrees below zero, snow is whipping down, the wind's blowing 30 miles an hour, and you're trying to write a program in a wall-less factory on the shores of Lake Michigan. Further imagine that you have only one week to implement a production-control system for this factory. And just to make things worse, the only time you have access to the system is during the graveyard shift, because every minute the production line is down, the company loses thousands of dollars.

This is exactly how I spent a week in January 1992 when implementing a client/server application for a major steel company. While my initial design was indoors, most of the programming occurred during 40 hours of graveyard-shift hell out in the cold where the software interfaced with vision equipment and robotic components on a manufacturing line.

This article describes the manufacturing process that was automated, the architecture of that system, the software tools used, the application prototyping and coding process, and the database implementation. The entire development had many constraints, the least of which was the one-week time limit. Ultimately, tools for developing the graphical user interface (GUI) and the structured query language (SQL) database made the difference in meeting the deadline. The application was completed in the last few hours of the allotted time, and it's been running 24 hours a day, seven days a week ever since.

The Process

The steel industry manufactures and sells many types of products in a variety of shapes, sizes, and elemental compositions. As different products move down the manufacturing line, it's necessary to stamp each one with an identifying signature (ID) designating the length, width, weight, and alloy composition. This enables the hundreds of steel products to be sorted, inventoried, and tracked.

Before I arrived at the steel mill in question, the process was performed manually with a special tool that looked like a sideways jackhammer. A production worker would receive from his supervisor a sheet of paper with the various IDs for all the products coming down the line. A worker would scan the paper, find the appropriate ID, and hammer it into the steel product at his station. My job was to automate the process, storing a copy of each ID along with secondary information in a database.

Automation would make the process safer and more efficient: The steel coming down the line was usually several hundred degrees Fahrenheit, so an automatic process would prevent serious burns, and the automatic stamper could perform ten times faster than a human. Management would be pleased because efficiency would increase by an order of magnitude, and labor would be happy because they were paid bonuses based on total output. The ingredients for a successful system were present--if I could deliver the system.

The System Architecture

The steel company already had an IBM mainframe computer which performed a variety of tasks and services for various departments within the company. The job was to integrate a specialized PC work-station to serve as the master behind the stamping operation. The IDs were transferred from the mainframe to the PC over a serial cable. Besides handling the ID, the PC performed several other functions, such as monitoring the position of the steel products and clamping the steel products once they got into position. A series of robotic arms, digital-to-analog converters, and vision devices worked together to secure the steel products for stamping.

Once a steel product was in place and its ID was displayed on the PC monitor, the production worker would visually verify that the ID was correct, then touch the monitor's touchscreen to send the ID to the automatic stamper. When the stamping was complete, the ID was written to a dBase file on the PC, which would then tell the robot to release the steel product so the next one in line could get stamped. Since the process was interactive, the worker could override the inventory ID at any point if it was incorrect.

The hardware was standard except for the PC designed for the project by Ziatech Corp. The PC had one 386 CPU and four 286 chips, four standard COM ports, and a capacitative touchscreen mounted on the monitor. DOS 5.0 and. Microsoft Windows 3.0 were installed on a partition for the 386 chip, and DOS 5.0 was installed on separate partitions for each of the 286 chips.

The 386 chip ran a program that had several responsibilities: receiving the data from the mainframe via a RS-422 cable, sending the ID to the automatic stamper via a RS-232 cable, and writing a record to a dBase file. Each of the 286 processors, on the other hand, ran programs which controlled robotic arms via RS-232 serial cables wired into Opto 22 boards. The robotic arms were responsible for clamping the steel products. Vision devices wired to the Opto 22 boards provided positioning feedback to the system.

The entire system was enclosed in an industrial-strength housing bolted to the concrete floor. The stamper, also bolted to the floor, sat between the system and the manufacturing line.

The Software Tools

The project specification dictated that the interactive stamping program on the 386 had to run under Microsoft Windows and be written in C. The robotic programs (running on the 286s) also had to be in C. The database format was dBase.

I used ProtoView 3.3 Dialog Editor to build the dialog boxes. I then used the ProtoGen 3.0 Code Generator to generate ANSI C code for the Windows application and Pioneer's Q&E Library to make calls to dBase via the code generated ProtoGen and ProtoView's SQLView 1.0. I compiled the interactive stamping program with Microsoft C 6.0 and the Microsoft 3.0 Software Development Kit (SDK) using Paintbrush to create bitmaps used in the Windows program. Microsoft C 6.0 was used to compile the robotic C programs, with Brief 3.0 as my primary editor.

The ProtoView tools utilize and manipulate bitmaps in a Windows application, generate and regenerate code, and link to a back-end database. In addition, the ProtoView Dialog Editor supports the use of bitmaps through a custom bitmap control. This was important, since bitmaps were used to display warning and danger conditions to the user. As a developer, I was able to easily hide and show the bitmap pictures via a timer message, thus creating the illusion of a flashing signal. Bitmaps are visually manipulated with the ProtoView Dialog Editor; see Figure 1.

The ProtoGen Code Generator generated code for a dialog box in less than two seconds on a 20-MHZ 386. (This is important when you're standing ankle deep in snow in the middle of the night with a 20-mile-an-hour wind hitting you in the face.) More importantly, I could add custom source code to the code originally generated by ProtoGen, make changes to the GUI, and rely on ProtoGen to regenerate code (with the new changes), while preserving my custom source code (see Listing One, page 23). My application had about ten dialog boxes; the average regeneration time was about 30 seconds.

I used the Q&E Library from Pioneer Software because of a group of ProtoView-supplied custom macros that integrated the Q&E Library into the ProtoView Dialog Editor. These macros make up SQLView and allow you to visually assign specific fields on the screen to their database counterparts. Once the dBase tables had been defined, all I had to do was visually assign (point-and-click) macros to the fields that were a part of the database scenario. SQLView handled all the necessary calls for inserting, updating, selecting, and deleting various records. The SQLView and Pioneer Software DLLs make a powerful combination for quickly building back-end support.

The Prototyping and Coding Phase

When I entered the factory the first night, all I had was a design document and my notebook computer. The PC workstation and the automatic stamper had been delivered that afternoon. My first task was to write the Windows program which accepted data from the host mainframe. I turned on my notebook computer and loaded Windows, then loaded the ProtoView Dialog Editor and ProtoGen Code Generator. With the dialog editor, I populated a dialog with a couple of string controls and saved the dialog to a resource file. Then, using ProtoGen, I attached the dialog box as the main window for my application and generated C code. This process took about three minutes.

Once the code was generated. I used Brief to add a SetTimer function call under the WM_INITDIALOG case statement to poll the serial port every one-tenth of a second. Since I had set a timer, I then had to add the WM_TIMER case statement to the code. This wasn't a problem because ProtoGen generates pairs of regeneration comments throughout the source code. If you place custom code between ProtoGen's regeneration comments, then your code will be preserved if you have to regenerate the application, as in Listing Two (page 23).

The next step was to add code to read data from the serial port. ProtoGen output lets you add functions to your code as long as you link in the supporting library. That means you can call any Windows API function or database functions from third-party database vendors who supply libraries. Consequently, serial port polling was accomplished using the Windows API ReadComm function.

ProtoGen also automatically generates variables for every control you place in a dialog box, regardless of control type. So, if you place a date control in a dialog box, ProtoGen generates an instance of a tm struct, thus making it easy to manipulate dates. Since I'd populated my dialog box with string controls, ProtoGen generated a character array for each string I defined.

ProtoView has its own API, with functions to facilitate data transfers. The data-transfer mechanism automatically moves the values of each application variable into their respective screen counterparts or vice versa. I supplied the ReadComm function (one of the character pointers ProtoGen generated) and invoked the transfer mechanism by calling ProtoView's vwUpdateScreen function. This was all that was needed to display incoming characters on the dialog box.

ProtoGen invokes either the Microsoft or Borland compiler from a menu option. The first program I wrote took about ten seconds to compile. ProtoGen also launches your program once you get a successful compile. I launched my program and watched as it began to display characters in my newly created string control.

I spent the first three nights designing the interface, which displayed information about the positioning of the steel products. Using timers and bitmaps, I simulated a flashing signal to the production worker on one of the dialog boxes by simply hiding and unhiding the bitmaps every half second. Once the vision devices detected the steel was in place, I showed the worker an "in-place" bitmap, telling him it was all right to send the steel ID to the automatic stamper. While the vision devices were busy detecting positioning parameters, data was downloaded from the host. If the ID from the host was acceptable, the worker touched the touchscreen to send the ID, character by character, to the automatic stamper.

Since the ProtoView is a "work-in-process" toolset, the code regeneration lets you make small changes to the interface, then regenerate it to support those changes. Thus, the development process becomes a cycle of incremental prototyping and production-code solidification, as shown in Figure 2.

The Database Implementation

As stated earlier, SQLView was used to gain back-end support. Every window designed with the ProtoView Dialog Editor can gain access to a variety of databases. SQLView is a DLL that contains a group of SQL macros that interface with Pioneer's Q&E Library and Microsoft's Open Database Connectivity Library (ODBC) to the window being designed. All you do is pick the fields belonging to a database table and the buttons executing SQL actions--SQLView does the rest. Also, SQLView is designed to connect to multiple tables in multiple databases, regardless of the database.

SQLView maps all of ProtoView's custom controls to the underlying SQL APIs. Microsoft and Pioneer support over 20 different relational databases, so integrating a ProtoView dialog to Oracle, Paradox, DB2, SQL Server, dBase, and the like is straightforward. ProtoView also provides automatic data conversion--for example, a dialog with one date control, one currency control, and one integer control can be mapped to a database table consisting of three 10-byte character fields. SQLView converts each data type to a character string if necessary or desired.

The ID being stamped and some data that reflected current operating conditions were stored in two dBase tables. SQLView allowed the same touchscreen button that sent data to the automatic stamper to send data to the database as well. SQLView also made it possible to pick exactly which fields on the screen to associate with a database table. A SQL Execute macro was attached to the button and a SQL Field macro was attached to each field. When touched, the macro scanned the window and inserted all fields with the Field macro into the database. Database connectivity was achieved in less than five minutes; see Figure 3.

Conclusion

In addition to staying warm, my goal that week was to develop a working application. My client knew what he wanted, but didn't know how to implement it. I knew computer programming, but knew very little of the particular industry. Once the client had defined his needs, it was a simple process of designing the architecture of the system, choosing the right tools, prototyping the application, and solidifying the code into a final working executable.



_PROTOTYPING AND PROGRAMMING DATABASE SYSTEMS_
by Miles Dempsey


[LISTING ONE]

//REGEN_FILEHEADING
//REGEN_FILEHEADING
/***************************************************************************
*   Source File: Warning.c
***************************************************************************/

#include <windows.h>
#include <pv.h>
#include "WARNING.h"

//REGEN_VARIABLES
//REGEN_VARIABLES

VIEW     hViewWarning;
HWND     hWndWarning;
LONG FAR PASCAL fnWarningWndProc(HWND, WORD, WORD, LONG);

int fnWarning(HWND hParentWnd)
{
   int   ReturnCode;

   VIEWPROC   lpfnfnWarningWndProc;
   //REGEN_BEGINFUNCTION
   //REGEN_BEGINFUNCTION

   lpfnfnWarningWndProc=(VIEWPROC)MakeProcInstance((FARPROC)
                                                      fnWarningWndProc,hInst);
   //REGEN_INITDLG
   //REGEN_INITDLG
   if(!(hViewWarning = vwCreateView(hInst,
                   "Warning",
                   hParentWnd,
                   lpfnfnWarningWndProc,
                   NULL)))
        return FALSE;
   vwSetFieldVar(hViewWarning, ID_WARNING, &nWarning);

   //REGEN_INITVIEW
   //REGEN_INITVIEW
   if((ReturnCode = vwShowModalView(hViewWarning)) == -1)
   {
        MessageBox(NULL, "Unable to display view", "System Error",
                   MB_SYSTEMMODAL | MB_ICONHAND | MB_OK);
        return FALSE;
   }
   //REGEN_TERMVIEW
   //REGEN_TERMVIEW
   FreeProcInstance((FARPROC)lpfnfnWarningWndProc);
   return(ReturnCode);
}

long FAR PASCAL fnWarningWndProc(HWND hWnd, WORD wMessage, WORD wParam,
                                                                  LONG lParam)

{
   GETVIEW;
   //REGEN_WINDOWPROCVARIABLES
   static int Opto22 = 0;
   //REGEN_WINDOWPROCVARIABLES
   switch(wMessage)
   {
       //REGEN_WNDPROC
       case WM_TIMER :
         switch (wParam)
         {
           case TIMER_LOOK_FOR_CLAMP:
             code which monitored one of the Opto 22 boards went here
             // Flash the bitmap until the steel is clamped
             if (!bFlash)
             {
               vwHideField (View, ID_WARNING);
               bFlash = TRUE;
             }
             else
             {
               vwUnHideField (View, ID_WARNING);
               bFlash = FALSE;
             }
             // When steel is clamped, kill the timer
             if ( Opto22 == FOUND )
               KillTimer (hWnd, TIMER_LOOK_FOR_CLAMP);
             break;
          }
          break;
       //REGEN_WNDPROC
       case WM_INITDIALOG :
          //REGEN_WM_INITDIALOG

         /* Custom code which starts a timer looking for feedback
          * from the vision instuments went here between the regeneration
          * comments which ProtoGen will preserve. */

          SetTimer (hWnd, TIMER_LOOK_FOR_CLAMP, 500, NULL);

          //REGEN_WM_INITDIALOG
          return TRUE;
case WM_COMMAND :
              switch(wParam)
              {
               case ID_WARNING :
               //REGEN_ID_WARNING
               //REGEN_ID_WARNING
               break;

               case ID_CONTINUEOPERATION :
               //REGEN_ID_CONTINUEOPERATION
               //REGEN_ID_CONTINUEOPERATION
               break;

               //REGEN_CUSTOMCOMMAND
               //REGEN_CUSTOMCOMMAND
              }
            break;
   }
   return DefViewProc(hWnd, wMessage, wParam, lParam);
}
//REGEN_CUSTOMCODE
//REGEN_CUSTOMCODE





[LISTING TWO]


long FAR PASCAL fnReadCommWndProc(HWND hWnd, WORD wMessage, WORD wParam,
                                                                  LONG lParam)

{
   switch(wMessage)
   {
       //REGEN_WNDPROC
       case WM_TIMER :
         switch (wParam)
         {
           case TIMER_LOOK_FOR_CHARACTER:
             // code to monitor the RS422 port
             // szString was generated by ProtoGen
             ReadComm (....,  szString);
             if ( lstrlen(szString) > 0 )
               vwUpdateScreen (View);
              break;
          }
          break;
       //REGEN_WNDPROC

       case WM_INITDIALOG :
          //REGEN_WM_INITDIALOG
          // Set a timer for every 1/10 of a second
          // The third parameter is milliseconds
          // 1000 = 1 second
          SetTimer (hWnd, TIMER_LOOK_FOR_CHARACTER, 100, NULL);
          //REGEN_WM_INITDIALOG
          return TRUE;
    }
   return DefViewProc(hWnd, wMessage, wParam, lParam);
}
//REGEN_CUSTOMCODE
//REGEN_CUSTOMCODE








Copyright © 1993, Dr. Dobb's Journal