DESIGNING A SYSTEM WITH

C EXECUTIVE


JMI Software Systems has always encouraged the use of data flow design techniques for multitasking applications. Chapter 2 of the C EXECUTIVE User Manual, 'Designing a System', begins with "The primary design goal of C EXECUTIVE and PSX is to provide a programming environment that both encourages and facilitates the use of data flow design methods."

JMI's key staff members have been using data flow design since 1978 for the analysis and design of complex multitasking real-time applications. The techniques are very powerful, yet very easy to use. Best of all, they can be applied using anything from a blackboard to a formal graphical design tool on a workstation.

The basic tenent is that the system is viewed from the point of data flowing through the system, rather than control flow or system component hierarchy. Using simple symbols for tasks (circles), flows of data (lines), sources and destinations of data (rectangles), and static data files (slanted line segments), a system can be quickly described for all members of a project team: software engineers, hardware engineers, project leaders, management, and marketing.

Traditional flowcharts, etc., do not show the system in terms of functional components and the various stages of data transformation within a system. Both concrete objects (communication ports, digital I/O devices, and other input and output sources/destinations can be easily identified along with the more abstract objects such as parsing modules, communication protocol stacks, data base access routines, etc.

Usually, marketing and management may only be interested in the interfaces on the periphery, while software engineers will follow the data streams to the innermost modules, where abstract data manipulations take place. Data flow diagrams are both simple, graphic, and detailed, since they can be layered, with each layer expanding upon the detail of the previous layer.

A data dictionary is used to capture and maintain details of each data stream and file, and psuedo-code (structured English) can be used to describe the algorithms within each modular task. When appropriate, it is a good idea to use state tables to document modules which can be viewed as finite state machines.

The combination of the above techniques has been proven on a wide variety of multitasking applications, yet the techniques can be taught in about an hour or so. These methods have been successfully used on the following customer applications employing C EXECUTIVE:

- mixing propellants for solid fuel rocket motors
- FAA enroute traffic control
- medical laboratory instruments
- communication systems
- multi-function printers
- cell phone monitoring
- U. S. Navy flight test range data acquisition system
- SCADA systems
- oil and gas well contol
- remote diagnostic console
- portable logic probe course reference
- dimensional gauging

When a system is designed using data flow techniques, the system might be portrayed as follows:

[data flow diagram]

Note that there are four modules (tasks or programs or processes, depending on the nomenclature of the specific operating system environment) - A, B, C, and D. Each module is an independent asynchronous entity, so that each can execute on its own individual time basis, and even in its own processor. Each module is data-driven, so that the arrival of data implies passing control to the module. In a distributed system, there may be two or more processors used to implement this system. The operating system is presumed to provide the necessary communication methods to allow all required data transfer and coordination.

Note that each module has one or more input data streams, and also one or more output data streams. The data streams from the outside world would typically represent data from a serial port, communication link, etc. The data streams between modules would represent a mechanism for inter-task communication provided by the target operating system. C EXECUTIVE and PSX provide data queues for this purpose. In the diagram above, each of the four modules suspends on its primary input data stream, waiting for a message to arrive. (If a module needs to monitor multiple streams, the select() system call can be used.) While it is waiting, it is suspended and uses no CPU resources. As soon as a message arrives, the module is awakened in priority order, and the module resumes execution by reading the message. The pseudo code for such a data-driven module would look like the following:

while (there is message)
    process the message
In C EXECUTIVE and PSX, the C language would look like:
moduleA()
    {
    FOREVER /* while (1) */
        {
        read (STDIN, buf, MSGSIZE);
        ...
        manipulate the data as required
        ...
        write (STDOUT, buf, OUTSIZE);
        ...
        more data manipulation
        ...
        ...
        write (STDERR, buf, OUTSIZE);
        }
    }

Notice that there are no open() nor close() calls, since C EXECUTIVE performs these automatically. This module never exits, but in those modules that do terminate, the trailing right curly brace (}) implies an exit() call. In a data flow design, modules are typically started upon system initialization and remain always active. If a module terminates, another module may have to restart it, of course.

Each module's algorithm usually can be expressed as top-to-bottom sequential logic flow. The structured pseudo code and the C code are both top-down, linear logic, easy to design and easy to get right the first time. Using this approach, the system designer can analyze the algorithm of each independent module, relying on the operating system's features to provide inter-task communication and task scheduling.

C EXECUTIVE and PSX allow the specification of all modules and queues from tables, although processes also can be dynamically created. The process configuration table for the system in the diagram would appear as follows:

taskA, procA, 300, uart1, que0,  que1,  T_ON, T_C, 0, 0, 0, 6
taskB, procB, 300, que1,  prt1,  que3,  T_ON, T_C, 0, 0, 0, 4
taskC, procC, 300, que0,  uart2, que2,  T_ON, T_C, 0, 0, 0, 4
taskD, procD, 300, que2,  com1,  dvnul, T_ON, T_C, 0, 0, 0, 2

The fields in the above table correspond to each process's:

1.  C function entry point
2.  process name
3.  stack size
4.  initial standard in device
5.  initial standard out device
6.  initial standard error device
7.  start/do not start upon system initialization
8.  language type
9.  optional period of cyclic execution
10. optional delay before first periodic execution
11. optional parameter passed to entry function.
12. process priority (procB and procC are equal priority). 

Note that for each independent module in the data flow diagram, there is a simple one-line definition of each process. For each inter-task communication stream, a data queue can be defined in the Device Configuration Table.

The Device Configuration table for the above system would look like the following:

"dvnul", nuldrv,  0, 0
"uart1", uartdrv, 0, &tty
"uart2", uartdrv, 1, &tty
"com1",  comdrv,  0, &tty
"prt1",  prtdrv,  0, &tty
"que0",  quedrv,  0, &queinit
"que1",  quedrv,  1, &queinit
"que2",  quedrv,  2, &queinit
"que3",  quedrv,  3, &queinit

The above table has, for each device, the following fields:

1.  device name
2.  device driver name
3.  minor device number
4.  address of initialization structure.

The ease of use of data flow design, coupled with the simple configuration of tasks and processes in C EXECUTIVE and PSX, allow a data flow diagram to be directly mapped into a running system.

Please refer to the description of our training course during which data flow design techniques are taught and then used to design the customer's application, then map it into C EXECUTIVE.

[JMI home page] Go to JMI home page

Copyright © 1997, 1998 JMI Software Systems, Inc.
Web page created by Ed Rathje and Alan Cleary - last updated July 21, 1998.