N O T I C E 

THIS DOCUMENT HAS BEEN REPRODUCED FROM 

MICROFICHE. ALTHOUGH IT IS RECOGNIZED THAT 

CERTAIN PORTIONS ARE ILLEGIBLE, IT IS BEING RELEASED 

IN THE INTEREST OF MAKING AVAILABLE AS MUCH 

INFORMATION AS POSSIBLE 
Thismicrofiche was

and, meets the

qualityspec-Ification

contained therein. A

poor blowback ima

Is the result of the

characteristics of the

original document.

L
A PETRI NET CONTROLLER

FOR DISTRIBUTED

HIERARCHICAL SYSTEMS

/V,4 4 l.V -/3 3.3

Center for Intelligent

Robotic Systems

for Space Exploration

Rensselaer Polytechnic Institute

Troy, New York 12180-3590

(NASA-CR-191862) A PETRI NET N93-16575

CONTROLLER FOR DISTRIBUTED

HIERARCHICAL SYSTEMS Thesis

(Rensselaer Polytechnic Inst.)

146 p

uncl as

G3/65 0140788

- -- WOW 7.
'

A PETRI NET CONTROLLER

FOR DISTRIBUTED

HIERARCHICAL SYSTEMS

,4/,4- 4GU-/333

by

Joseph E. Peck

Rensselaer Polytechnic Institute

Electrical, Computer, and Systems Engineering Department

Troy, New York 12180-3590

December 1991

CIRSSE REPORT #109

0
CONTENTS

LIST OF TABLES ................................. v

LIST OF FIGURES ................................ vii

ACKNOWLEDGEMENT ............................. viii

ABSTRACT .................................... ix

1. Introduction .. .................. . .. ....... ..... 1

1.1 Motivation . . . .. .. .. .. .. . . . . . . . . . . . . . . . . . . . . 1

1.2 The CIRSSE Dual Arm Robotic Testbed ................ 1

1.3 Thesis Organization .. .. ... ... ... . . . . . . . . . . . . . . . 3

2. CURRENT PETRI NET THEORY AND APPLICATIONS ........ 4

2.1 Introduction . .. ... .. .. .. .. .. . . . .. . . .. .. . .. .. 4

2.2 Petri Net Theory ..... .. ....... .... .. .. ... .. .. 4

2.3 Petri Net Tools .... .. .. ....... .. ....... .. .. .. 6

2.3.1 GreatSPN . .. ........... . .. . ... .... . .. . . 6

2.3.2 SPNP ............................... 7

2.3.3 Xpa ................................ 7

2.4 Petri Net Controllers .. . .......... . .. .. .. .. . .. .. 7

2.4.1 Petri Net Controller ........ . ..... . .. .. .... 8

2.4.2 TokenPasser ................ . . ... ... ... . 8

2.4.3 DPNC ............................... 9

2.5 Summary .. ... ............. ........... .. .. 9

3. PROBLEM STATEMENT AND SOLUTION ................ 11

3.1 Introduction .. ...... ......... .... .. ..... .. .. 11

3.2 Project Specification .......... .. .... ..... .. .. . . 11

3.3 Project Design ........ ....... .... .. ... . . .. .. 12

3.3.1 Petri Net Transducer Extensions . .... . . . .. .. ... . 12

3.3.2 CIRSSE Testbed Operating System .. ..... .... .. .. 13

3.3.3 The Data Object Manager ... .. .... ... .. .. .. .. 14

ii

_ r • ^^' 
3'3.4 Player Design '''''.'.^''''^.'^'','..^^'' 14

3.3_5 Display Desi gn _^ ^_ _ _ _^ , _', ' , , , ' ^ ^ ^^ ' . . ' ' lT

3.3.8 Function Execution ' '. . . . ' . . . ' '' ' ' ' ' ^' . , . . . 17

3.3'T Tape Issues .. .' '' ' . . , ' ^ ^ ^ ' .' ^ ^ . ' ' ^ ^ , . ' ' 19

3.4 Summary ....'''....,^,^.^^^'^''..^^^....' 19

4. USING THE CONTROLLER ^ . . . ' , ' ' . ' ^ , ^ , ^ , ,^ ,_ ^ ^ ^ ^ ^ 20

4`1 Introduction '''...^'.,,''.^....^.'........'. 20

4.2 Application Design Methodology ^' ^` ^ ^^ `` ^` '. .' . ., ' , 20

4.3 Application Configuration File ...'...'.....'..,.,^,, 24

4.1 Petr i Net Files ''''''.,.'''''......'. 25

4.4.1 Player File '''.'.''..''.'..'.'....,''''' 25

4'4'2 Enablina and Post Functions '''''.'..,..'.'.''' 27

4.4' 3 Display File ,.^^ ^^'.' '' ^' '' '' . ' ^ ^ ^^' ', ^, 27

4.5 User Interface ''''.'. . .'...........'..''''' 28

4J5 ' 1 Display Control '.'.'.,.'.'...'.'..''''.., 20

4.5.2 Player Control .'..''.',.'.'',.......'^..' 29

4.6 Summary''''''''^'^^'^^^^^^`^^`.^^`'..'.. 29

5. IMPLEMENTATION VS. THEORY '''..'.'''..'........ 31

5.1 lotrmdoction ' ' . ' . . . . . ' , . . . , . ' . ' . . . ' . ' . . ' . . . , 31

5'2 Analysis of Distributed Petri Nets .................... 31

5.3 Execution Algorithm '''...'......,,^^^,^^___,^_ 34

5.4 Summary''''''''''''^^^.....'...'''.'.''. 37

6. CASE STUDY: THE C7RSSETESTBED . .. .. .. .. . . . .. .. .. 30

6.1 Introduction , . .,.., , .... .. . .' '. .. '. '. '' . '' .. 30

6'2 The Dual Arm Robotic Testbed.'.....'........'.... 38

6.3 Case 0: Camera CaUbcatima ..'''..........,..,.... AO

6'3.1 ]] '''...'.'.'....'...,'......,. 40

6.3' 3 Motion Coordinator .'...'..'......'''..,.. 43

8.3,3 Vision Coordinator ..'..,............,..... 43

6.4 Case 1: Strut Insertion ...,'.'............'..,.,. 46

6.4` 1 D ...,,,,,.................,... 48

iii

` "W,
M

6.4.2 Motion Coordinator ................ ....... 

6.4.3 Vision Coordinator .... . .. .. . .. . .. . . .. .. .. . 

6.4.4 Path Planner Coordinator .. . .. . ... . .. . .. .. .. . 

6.5 Summary

... ...... .. .. ... .. . . .. .. .. .. .. ... 

7. CONCLUSIONS AND i UTURE RESEARCH . , .............. 

7.1 Conclusions .. ......... . .. .. ... . . .... .. .. .. . 

7.2 Future Research and Modifications ................... 

LITERATURE CITED .............................. 

APPENDICES ................................... 

A. Local Enabling and Post Functions .. ... . ... . . . . .. .. .. .. . 

A.1 Enabling Functions .... .. .. .. . .. .. .. .. .. .... .. . 

A.2 Post Functions .... .. .... .. . .... .. .. .. ...... . 

B. Header Files ................................... 

B.1 GlobaLvar.h — The Global Variables .................. 

B.2 GlobaLvar.p — The Global Variable Prototypes ..... .... .. . 

B.3 G1obaLdefh — The Global Definitions ................. 

BA msg.h — The Controller CTOS Messages . .. .. .. .. .. ..... 

C. Player Software ... ........ .. ... .... .... .... .. ... 

CA makefcle — The Player Makefile .................. ... 

C.2 play_eh.c — The Player Event Handler ................. 

C.3 Xplayx — Tests and Fires Transitions .... .. .. .... .. ... 

CA enable_func.c — Local and Remote Enabling Functions ..... .. . 

C.5 post_func.c — Local and Remote Post Functions ............ 

C.6 tape.c — Tape Commands ........................ 

C.7 load_net.c — Loads the Petri Net Configuration File .......... 

C.8 msgs.c — Sends Various Messages ... .... .. ...... .. .. . 1

C.9 var_manx — Manages the Variables for Local Functions ....... 1

D. Display Software ................................ 11

D.1 Nlakefcle — The Display Makefile .................... 11

D.2 disp_eh.c — The Display Event Handler ................ 11

iv
D.3 Xdraw.c — Performs All X-Drawing Actions ... ........... 116

DA Xsetup.c — Initializes the Windowing System .. .. ......... 124

D.5 manip_net.c — Performs Scaling and Shifting of Display . .. . .. . 128

D.6 monitors — Processes X-Window Events .. .. .. .. .. . .. .. 132

D.7 Xinter.c — User Selection of Places and Transitions .......... 135

v
LIST OF TABLES

Table 4.1 Display Commands ........................ 29

Table 4.2 ?'layer, Commands ........................ 30

f vi

I 
LIST OF FIGURES

Figure 1.1 The CIRSSE Dual Arm Robotic Testbed ............ 2

Figure 2.1 An Example Petri Net Transducer ................ 5

Figure 3.1 The Extended Petri Net Transducer ............... 13

Figure 3.2 Player Code Flow .. .. .. . .. .. .. . . . . . ... . . .. 16

Figure 3.3 Display Code Flow ... .. .. .. .... .. . .. .. . .. . 18

Figure 4.1 Petri Net Interconnection . . . . . . . . . . . . .. . . . . . . 21

Figure 4.2 A Petri Net Hierarchy ...... ... .. .. ... . .. . .. 22

Figure 4.3 The Coordination Structure . ... .. .. .. .. . .. .. .. 23

Figure 5.1 A Nell-Formed Block .. ... .. ..... .. ....... .. 32

Figure 5.2 A Coordination Structure Comparison . . .. . .. .. . . .. 35

Figure 5.3 An Unfair Example . .. .. . . . .. . . . . .. . . . .. .. . 36

Figure 6.1 The Hierarchy of an Intelligent Machine ...... .. .. .. 39

Figure 6.2 Case 0: Dispatcher Display and Player ............. 41

Figure 6.3 Case 0: Motion Coordinator Display and Player . . .. .. .. 44

Figure 6.4 Case 0: Vision Coordinator Display and Player . ...... . 45

Figure 6.5 Case Study 1: Strut Insertion . ...... ..... ...... 47

Figure 6.6 Case 1: Dispatcher Display ... .... .. .. ... ...... 48

Figure 6.7 Case 1: Dispatcher Player; Note the Complexity versus the

Dispatcher Display Petri Net . .. .. ... .. .. .. ... .. 49

Figure 6.8 Case 1: Motion Coordinator Player ............... 52

Figure 6.9 Case 1: Vision Coordinator Player .. .. .. ..... .. .. 53

Figure 6.10 Case 1: Path Planner Coordinator Player . . . . . . .V. . . . . 54

vii

i
ACKNOWLEDGEMENT

I would like to thank Professor Alan Desrochers for the opportunity he gave me

to work for CIRSSE, as well as for his support and guidance during my research

I would also like to thank Don Lefebvre for his assistance in developing the Petri

net requirements and in adapting the software to the CTOS environment. My

appreciation goes out to Keith Fieldhouse for his assistance in tracking down some

subtle programming errors. I also wish to thank Steve Murphy for his last minute

assistance in generating the testbed figures. Finally, I need to thank Mary Sargen

for her continual support throughout my academic career.

Viii
CHAPTER 1

Introduction

1.1 Motivation

The contents of this paper and the associated software came about as a direct result of certain needs for the Center for Intelligent Robotic Systems for Space

Exploration (CIRSSE) dual arm robotic testbed at Rensselaer. Relatively independent research groups have been working on various subsystems of a robotic platform

capable of supervised autonomy. Each of these subsystems have matured to the

point that significant effort is now going into the integration of the components

for high level testing and development. To successfully integrate the testbed, tools

were required to 1) model the system; 2) integrate the subsystems; and 3) obtain

user interaction. This paper presents a Petri net based controller which satisfies

these three needs. An underlying theme in each of these requirements is flexibility,

such that future expansion and development of the system will not render today's

controller obsolete.

1.2 The CIFSSE Dual Arm Robotic Testbed

The architecture of the CIRSSE dual arm robotic testbed was developed to

provide a platform for research ancl, development of a space-based robotic system

[9] [26]. The hardware consists of two PUMA manipulators connected to carts on a

common linear track, with a laser and five camera vision system. The manipulator

hardware is shown in Figure 1.1. Software servicers have been developed to perform

the low level interactions with the hardware, providing a level of abstraction for

simplified application development. This testbed is currently supporting a number of research projects, including: visual object recognition; visual servoing; strut

1
Figure 1.1. The CIRSSE Dual Arm Robotic Testbed

-- .- - - • %W-
3

and node assembly and disassembly; two arm coordination and control; and path

planning with collision avoidance.

1.3 Thesis Organization

Chapter 1 presents the motivation behind this thesis, and briefly discusses the

CIRSSE testbed. Chapter 2 provides a brief description of current Petri net theory,

tools and controllers. Chapter 3 presents the problem description, as well as the

proposed implementation of the solution. Chapter 4 details the use of the controller

itself, both in setting up and actually running the software. Chapter o discusses the

controller's conformity to Petri net theory. Chapter 6 presents two -ase studies in

the CIRSSE testbed environment. Chapter 7 summarizes the results of this project,

and provides directions for future work. Appendix A contains the descriptions of

the currently available enabling and post functions. The software for this controller

implementation is contained in the remaining appendices. Appendix B contains the

header files, Appendix C contains the source code for the player task, and Appendix

D contains the source code for the display task.

E^
CHAPTER 

CURRENT PETRI NET THEORY AND APPLICATIONS

2.1 Introduction

This chapter describes several aspects of Petri net theory relevant to this

project. Current tools aiding the design and analysis of Petri nets are discussed,

and two existing Petri net controllers are presented.

2.2 Petri Net Theory

Petri nets are a graphical and mathematical modeling tool for discrete event

dynamic systems (121 (141. They are particularly well suited to modeling asynchronous, synchronous, and concurrent actions, which occur extensively in most

large robotics and automation applications (11(151. One representation of a Petri

net is a weighted bipartite directed multigraph, whose node types are called transitions and places. Places and transitions are interconnected by arcs, termed input

arcs and output arcs with respect to the connected transition. Each place may contain some non-negative quantity of tokens, and this marking indicates the state of

the system. The firing of a transition represents an event that changes the state of

the system, thereby changing the marking of the places. A Generalized Stochastic

Petri Net (GSPN) is an ordinary Petri net whose transitions may take a deterministic period of time to fire. A transition is enabled to fire when each of its input

places contain at least as many tokens as the weight of its associated input arc. An

enabled transition may fire at any time, and that firing consists of three phases:

1) the enabiing tokens are removed from the input places; 2) some action may be 

performed which may cause a time delay; and 3) once the action is complete, tokens

are added to the output places.
A Petri Net Transducer (PNT) (22] (24] is an extension of a GSPN which add

another enabling condition to the firing requirements of a transition. An input tape

composed of members of the input alphabet is passed to the PNT, whose transition

possess an optional tape requirement. A transition with a tape requirement will be

enabled only if the head of the tape contains the proper command and its token

requirements are met. These extensions make PNT's a more powerful modeling

tool, but it does make the analysis of the Petri net more complicated.

Parallel

' Actionl

Sequential

Figure 2.1: An Example Petri Net Transducer

An example PNT is shown in Figure 2.1. The two initial transitions each

require a different tape command in order to fire. If Parallel is at the head of the

tape, the upper patio will be. taken, while if Sequential is at the head the lower

path will be followed. Both paths perform two actions, but the upper pa;;h performs

Actioal and Action2 concurrently, while the lower path performs Acti ^n3 and

6
Action4 sequentially.

2.3 Petri Net Tools

r.

Although Petri nets have been used extensively in manufacturing environ

ments, to date there is no one package that provides full design and analysis capa

bilities. Petri nets are inherently graphical, and lend themselves nicely to Computer

Aided Design entry. However, the analysis capability of the existing tools seems to

be inversely proportional to their ease of use and quality of interface.

2.3.1 GreatSPN

GreatSPN (31 offers a graphical user interface for the construction, editing and

analysis of Petri nets. This package was developed at the University of Torino

Italy, as a tool for the specification and performance analysis of computer systems,

and has since evolved into a general Petri net tool. GreatSPN supports immediate,

stochastic and timed transitions, as well as inhibitor arcs. The Petri net can be

analyzed for basic. properties, such as p and t invariants, boundedness, steady state

token distribution, and deadlock. Performance can be determined as well in terms

of token throughput. In addition to the screen display, the software can also save

the net in a postscript file for printing hardcopy output.

Note that GreatSPN is not without drawbacks. Its analysis capabilities are

not fully implemented yet, and the abilities of the existing analysis options degrade 

with larger Petri nets. Finally, although the graphical user interface represents an

advance over typical text based approaches, some aspects of the interface are still

awkward to use. 
L -

2.3.2 SPNP

SPNP (4] is a text based Petri net analysis package developed at Duke Univer.

sity that provides a wide variety of analysis capabilities. The Petri net is described

as a series of C function calls, which also define the type of analysis desired. SPNP

builds the reachability graph, and from this it can determine the steady-state Ma.rkov

chain, token distributions and throughput, and a host of other parameters.

Although the SPNP software itself can analyze a vary large net, entering the

C function calls is error prone and difficult to verify. One approach to this problem

is to use a graphically oriented design program, and convert the stored information

into the desired format. GreatSPN2SPNP [13), written at Rensselaer Polytechnic

Institute, is a conversion program that translates a GreatSPN output file into a

suitable SPNP input file.

2.3.3 Xpn

Xpn [81 is a Petri net design tool being developed at Rensselaer Polytechnic

Institute featuring a full graphical user interface running under X-windows. The

created Petri nets may be stored in a variety of formats, suitable for use with other

packages such as GreatSPN, SPNP, as well as the controller presented in this thesis.

Note, however, that Xpn offers no analysis capability and is solely used for the net

design. Currently, this package is under development, and does not yet fully support

all file formats.

2.4 Petri Net Controllers

Petri nets have been used in industry for the modeling of systems, and many

dedicated controllers have been developed with the aid of those models. Recent work

at CIRSSE has been geared towards developing general Petri net controllers, for use

in distributed hierarchical systems. Two such controllers developed at CIRSSE were

...-.-- 
submitted as Masters Projects in 1991. Although both controllers were designed to

solve the same general problem, they possess very different implementations. These

two, along with a manufacturing implementation, are described below to highlight

their differences and to provide a basis of evaluation for the controller presented in

this thesis. 

2.4.1 Petri Net Controller

The Petri Net Controller (PNC) [5] [16] was developed to ease the difficulty in

organizing and controlling manufacturing stations. It was one of the first implementations to abstract itself from a direct hardware interface, and instead executed on 

a general purpose computer. The capabilities of PNC are based within the places

of the Petri net, where different types of places are used to represent and perform

different actions. Macro places represent an embedded subnet, action places interact

with the external world, and several other types exist as well.

Although a hierarchical arrangement of Petri nets is possible through the use

of macro places, this organization is still executed on only a single computer. There

are no built in means of distributing the controller itself over multiple machines.

Additionally, the macro places allow for only one entry point to a particular sub-

-. net, which limits flexibility. Finally, the execution algorithm as implemented does

not preserve the Petri net property of fairness, and special care must be made in 

designing each Petri net.

2.4.2 TokenPasser

TokenPasser [11] was designed to allow for the rapid prototyping of a distributed hierarchical control system which utilizes Colored Petri Net Transducers.

Individual Petri nets, each with their own display, can be distributed on different

computers. Each transition can execute a function call whenever it is fired, allowing 

SIR ^k^^... ,
for basic controller operation. The implementation of TokenPasser does not le

itself to use as a full fledged controller. However, it does provide performance d

through simulation, which can be extremely useful in determining communicat

g g

delays between various configurations. Designing a new Petri net application 

^

' quires that the user write a series of C function calls to be compiled and linked w

I

the controller software which define and initialize the net structure.

2.4.3 DPNC

Distributed Petri Net Controller (DPNC) (2) is a fuller controller implem

tation for distributed systems than TokenPasser, designed with control as a m

objective, as opposed to simulation. A series of players are connected in a token ri

fashion, with one central display. This controller executes a single Petri net, w

individual sections being executed on the separate players. DPNC uses GreatSP

to design the Petri net, and the resulting definition file is converted into C functio

by a UNLY script. These C functions are compiled and linked with the control

code itself, as is the case with TokenPasser. Additionally, any function calls th

are associated with the firing of a transition must be written, compiled and link

as well. The single display is both a blessing and a curse. The user need on

concern himself with one window on the screen, and all action occurs in this o

location. However, the Petri net for any real controller will be far too large to 

on a single screen, and any attempt to do so will result in a cluttered and confusi

t

representation. Like PNC, this controller does not preserve the Petri net prope

of fairness, and requires careful Petri net design.

V

2.5 Summary

Petri nets are a powerful tool for the modeling and analysis of discrete eve

dynamic systems. A Petri net based controller, with a fixed embedded Petri n

^._._._.. _._... • _^;.._....

..—ter – ^ -

_

-- ---
10

or some more flexible arrangement capable of using an arbitrary Petri net, can be

designed, analyzed and verified before the actual implementation. Additionally, any

desired modifications to the controller can be evaluated before implementation as

well. Tools such as GreatSPN may be used to graphically design and modify the

Petri nets, while other tools such as SPNP can be used for detailed analysis.

To date, only PNC has been used in conjunction with physical hardware.

It was used to control a machining workstation based on a Cincinatti Milacron

5VC Machining Center, which produced a variety of parts. The other controllers,

TokenPasser and DPNC, were not developed sufficiently to be used in a real system.

However, with additional work and effort they would have resulted in a more flexible

means of controlling and monitoring a distributed, hierarchical system.

I .
CHAPTER 

PROBLEM STATEMENT AND SOLUTION 

3.1 Introduction

This chapter details the requirements for the Petri Net controller, and discusses

the chosen implementation. This controller supports a distributed, heterogeneous,

hierarchical system with flexible execution and display options.

3.2 Project Specification

The requirements for this project are geared towards a general Petri net controller, and are not specific to its initial application, i.e., the CIRSSE testbed. First

of all, it must support a distributed system. It is assumed that the application

can execute on multiple processors, not necessarily in the same machine or even

location. Note that the term distributed not only applies to the hardware in the

system, but to the actual controller components as well. The overall system may

be heterogeneous, in the sense that the individual computers may be running different operating systems or even vary in architecture. The controller must allow

--. for hierarchical interconnections between the individual Petri nets, as a large class

of systems are ideally controlled with this configuration. Graphical displays must

be able to represent the actual executing Petri net, as well as subsets of places and

transitions to provide a summary of the entire application. Finally, the development

of a new application should not require the recompilation of the controller itself, i.e.,

its configuration should be data driven.

11
K"

12 

3.3 Project Design

The controller is broken into two distinct classes of processes: players and

displays. The players are responsible for executing the Petri nets which actually

perform the control of the system. As tokens flow through the net, the player

performs any necessary interactions with other players and the external world. The

displays are responsible for presenting the state of the system to the user, and

provide some means of controlling the players. It is extremely important to recognize

that the players and displays are completely separate entities, and that the players

can execute even in the complete absence of the display processes. However, most

applications will include the displays as a means of monitoring and controlling the

execution of the players. To this end, the display contents are highly configurable

to aid in the meaningful representation of the underlying player Petri nets.

3.3.1 Petri Net Transducer Extensions

The concept of PNTs is extended for this application, providing for a more

efficient and potiverful means of actually controlling a system. This extension is

made in the form of an additional enabling requirement, called an enabling function.

This enabling function returns a Boolean value indicating the state of an external

condition. Although this extension can b modeled by adding an additional place

plus inhibitor arcs to the Petri net for each possible tape command, it is not readily

implemented as such. A second extension is the inclusion of post functions, which are

executed with the firing of transitions. These post functions are the main mechanism

of performing an external action. These extensions are shown in Figure 3.1, where

the enabling condition of the transition consists of token requirements, an enabling

function, and a tape command. The firing of the transition causes the post function

to be executed.
4post Function

Tape Command --- %

Enabling Function ,%%

i

• i^

1

Figure 3. 1: The Extended Petri Net Transducer

3.3.2 CIRSSE Testbed Operating System

The CIRSSE Testbed Operating System (CTOS) (61 [9] (26] was developed t

facilitate the execution of applications which consist of multiple tasks and requir

intertask or interprocessor coramiluication. CTOS greatly simplifies design of 

distributed application, and forms the infrastructure for development on the CIRSSE

testbed. CTOS is an extension of the base operating systems at CIRSSE, and ha

been implemented for both UNIX and VxWorks.

CTOS offers an environment for conveniently distributing tasks and executing

a distributed application. A distributed application can be started with a singl

command line, through the use of configuration files. These application configura

tion files contain the list of tasks to be loaded and what machines to run them on

as well as any initial parameters to pass to the individual tasks. Reconfiguring an

application involves simply editing this file, and rerunning the application. No othe

parameters need be changed.
Each task is assigned a symbolic name in the application configuration file,

and it is this name that other tasks use to perform interprocess communication. I

one task wishes to communicate with another, it first queries CTOS for the task id

corresponding to the symbolic name of the other task. The task then uses CTOS

message passing routines to perform the communication, where the task id is used

to identify the recipient of the message.

Programs to be executed as CTOS tasks must be designed to exist in an event

driven environment. These CTOS tasks are often called event handlers, due to

their internal construction and external interface. In general, an event handler task

is asleep until it receives a message indicating that there is some work for it to

perform. The event handler is wakened, and performs the appropriate actions. It

then puts itself back to sleep.

!.

3.3.3 The Data Object Manager

One major concern of any distributed system is the location and accessibility

of data objects. A Data Object Manager (DOM) [9] has been developed at CIRSSE

to solve many data storage issues and provide a consistent interface to manipulating

those objects. Any CTOS task can access the DOM, which offers a variety of

capabilities. Data objects can be created, modified, renamed, deleted, copied and

more. Oftentimes the existence of a particular data object is represented as a place

in a Petri net; this place serves as a precondition for the firing of a transition which

performs some action involving that object.

3.3.4 Player Design

The player task is responsible for the execution of the Petri net that actually

controls the system. This involves the selection and firing of individual transitions,
15

and interfacing with the tasks that perform actions. Another significant responsibility is notifying all interested display tasks of changes in the state of the Petri net.

Figure 3.2 shows a high level view of the operation of the player code.

The player code spends the majority of its time in the Petri net execution

phase. While there are no messages pending, the player is attempting to fire transitions. There are two execution modes, continuous and single-s tep. In continuous

mode, the player repeatedly examines the enabling status of all transitions, and

fires those that are enabled. In single-step mode, the player repeatedly examines

the enabling status of those transitions which are not displayed in any display, and

individually examines those transitions which are clicked on in the display. As soon

as a message is received, the player exits from this enabling checking mode, and

processes all of the pending messages. Once there are no more pending messages,

it reenters the enabling checknn1 ; mode. These messages include the arrival of tokens from other players, the tog.ing of player modes, and various CTOS commands

such as application exit. The single-step mode is especially useful for debugging or

user control of the system. Note that each player can be in either continuous or

single-step regardless of the modes in the other players.

Petri net theory states that the firing of an enabled transition should occur

without regard to the other transitions in the Petri net. There should be no particular order in which the transitions are examined for possible firing, or the execution

of the Petri net may not follow the behavior predicted by the model. Therefore,

in terms of theory an ideal implementation woeld randomly select which transition

to examine as it executed the Petri net. However, a controller is also concerned

with speed, and in a sizable net with a small number of enabled transitions, a pure

random selection con result in an undesirable delay. A hybrid random-linear approach was taken. A randoin transition is selected to examine. If it is enabled, it is

fired. Otherwise, the transitions are examined in order until an enabled transition
Start

Load Configuration File

Send ID Requests for Remote Places

Respond to Place ID Requests from Other Players

Respond to Place and Transition ID Requests from Displays

Build Display Notification Lists

Store Place ID Information from Replies

Begin Petri Net Execution

Cleanup Resources

Exit

Figure 3.2: Player Code Flow
r

11

is found and fired. After the transition is fired, the process begins again with the

random selection. This provides for an arbitrary firing sequence, while maintaining

real world performance.

3.3,5 Display Design

The display task pruvides the user with a graphical representation of the status

of the system. These displays are highly configurable, and can serve a wide variety

of purposes. They do not need to mirror the underl ying player Petri net, and can

be used to provide a simplified representation of a particular net, or even a global

representation of the entire collection of nets. Figure 3.3 shows a high level view of

the operation of the display code. The parallel execution blocks in the flow indicate

where a monitoring task is spawned. This spawned task sits in a loop monitoring

the display window for user input and other X-window events. Whenever an event

occurs that is of importance to the display event handler, a message is sent. The

event handler then takes whatever action is appropriate. The display also receives

messages from the various player tasks, indicating that some aspect of the Petri net

status has changed. These can include tokens being removed or added to a place,

or transitions beginning or ending to fire. Transitions in the display can correspond

to two transitions in the player tasks, the firing of one causes the transition in the

display to be highlighted, while the firing of the other completes some action and

unhighlights the display transition.

3.3.6 Function Execution

One of the most important features of a controller is the ability to interact with

the external world. Without this ability, the controller is reduced to a simulator.

Due to this importance, an extremely flexible and powerful mechanism had to be

developed to handle this interaction.
IL

_,W, :aw.

Figure 3.3: Display Code Flow
19

The controller supports enabling functions and post functions. Each of these

is split into two classes, local or remote. The local functions are those that are

compiled into the controller itself, while remote functions are those that are executed

by a separate task. The local functions are geared towards looping or checking the

status of some variable in the DOM. The external functions perform actions such as

moving a robot, taking a stereo picture, etc. When a remote function needs to be

executed, the player sends a message Lo the task capable of performing the operation,

informing it of which partic,ilar action is requested and what data objects to use.

The task name, action, and data objects are specified in the player configuration

fiie.

3.3.7 Tape Issues

This controller fully supports the concept of a PNT input tape. Transitions

can possess an optional tape command, which is an additional enabling requirement.

These tape requirements can be used to parse a high-level language into lower level

components, aiding in the decomposition of tasks. Although the player itself can

accept an input tape and process its contents, no CTOS task exists for actually

sending a tape to the player. As stated earlier, the tape commands can be implemented as a group of input piaces, and r;urrent Petri net designs in this thesis are

utilizing that approach.

3.4 Summary

i The controller has been designed to meet all of the current requirements of

the CIRSSE dual arm robotic testbed, and in fact exceeds them in order to provide

a -viable system for future applications and research.
I.

CHAPTER 4

USING THE CONTROLLER

4.1 Introduction

This chapter provides a brief user manual for designing and implementing an

application utilizing this controller. Design concepts, as well as technical details concerning the related configuration files are presented and discussed. The commands

available through the displays at runtime are also described.

4.2 Application Design Methodology

A typical application consists of three to five player tasks, and approximately

the same number of display tasks. The primary work is performed in defining the

player Petri nets and their interconnections. The display Petri nets are more often

than not a stripped down version of the player Petri nets, with such structures as

buffers or communication points omitted for clarity in the display.

The player Petri nets are interconnected via local and remote places. A local

place is defined as a place that is native to the player Petri net in question, while a

remote place is one which is native to some other player. This is best demonstrated

with an example. Figure 4.1 shows three player Petri nets.

The first is a global net which performs two distinct actions. This net can be

broken into two subnets, shown at the bottom. Note that the place in-progress

appears in both subnets. The distinction is that in-progress is local to subnet 2,

and remote to subnet 1. A remote place in a net does not exist as a regular place,

but is actually a lint: to the local place in the remote net. The remote net can be on

the same processor, a different processor within a single VME cage, or even across

the ethernet network, and the link provides the interconnection to that Petri net.

20
r

r

r

r

r

I .." I

r 2

Ready In-PMZM" Done

•

Actions Action2

"

IN

II

\

\

\

N `

♦♦ a

Ready In—progrm In_progress Done

• 

A doal

U (D(remote) 0--F--O (10ca1) Acdm2

Figure 4.1; Petri Net Interconnection

The controller itself does not enforce the use of any particular interconnection

scheme, however, one should be adopted if the analysis of the Petri net is desired

The two case studies presented at the end of this paper are organized in a hierarchical fashion, and a requirement for both is the ability to analyze the system

and provide a consistent interface between modules. A consistent interconnection

strategy provides two benefits: only one method of analysis needs to be established

for the system as a whole; and the designers of new Petri nets in the system have

I a template for interconnection to follow. A hierarchical organization usually follows the principle of Increasing Precision with Decreasing Intelligence [17] [19]. The 

highest intelligence and global responsibility resides in the top of the tree, while

the lowest level functional abilities he along the bottom. Levels inbetween serve

j as coordinators, taking the higher level instructions and breaking them into a form

usable by the lower level. This corresponds to a situation where we would like a

single transition in a higher Petri net to request that a lower Petri net perform some

I:
Actionl Action2

xxaay In-pmgm Dow

22

action for it. The concept of this structure is shown in Figure 4.2, where the high 

level functions Actionl and Action2 correspond to the indicated subnets.

Figure 4.2: A Petri Net Hierarchy

Petri nets to be used in the CIR.SSE testbed use a formal coordination structure to provide this functionality. Each level in the Petri net hierarchy can only

perform a single action at a time for the level above it. This does not mean that

parallelism cannot occur within each Petri net, only that a net can only satisfy one

request at a time from the higher levels. This coordination structure is shown in

Figure 4.3, detailing the necessary components in both Petri nets. The single transitions in Figure 4.2 have been replaced with two transitions and a place. The place

is used to indicate that the requested operation is in progress. When the Petri net is

available, the places avail and S have tokens in them. S is a semaphore indicating

whether the net is currently performing some action. if not, begin can fire, placing

a token in in-progress and I. It also places a token into one of the request action

places, which indicates which operation is to be performed. This example Petri net
can perform three possible actions, whose request arcs are shown as dotted line

Only one of these arcs should actually exist for a given begin transition. The tra

sition start can now fire, putting a token in ready. Now the first transition of t

requested action may be fired. Once the operation is complete, a token is put i

place done. The transition finish is then enabled, and upon firing puts a tok

in place O. This enables transition end to fire, which restores the semaphore an

allows the Petri net to process another operation request.

be& in—pmgm end

Figure 4.3: The Coordination Structure
4.3 Application Configuration File

2

The entire controller application consists of CTOS tasks, which are execute

through the aid of a CTOS applicaL I)n configuration file. This file details the dis

tribution of tasks, their symbolic names for interprocess communication, and any

initial parameters required by the individual tasks.

The individual tasks may be executed on any machine in the network, so long

as it is running CTOS. Prior to declaring which tasks to run, the machine to load

them on must be defined. This is done with the line:

chassis machine-name

This indicates that the tasks after this line are to be started on the machine specified

by machine-name. Multiple chassis lines may be placed in the file in order to

distribute the tasks over the various machines.

The player task accepts only one parameter, which indicates which configuration file to use. Here are the lines corresponding to a player task and its parameter

task play-eh ..playerl

args playerl netl

The keyword task indicates that this line defines a symbolic name for a task to be

executed. The CTOS task play-eh is the player program, and in this example i

is referenced by the symbolic name playerl. The keyword args indicates that the

line defines a parameter to be passed to a task. In this instance, the string netl is

passed to the task with the symbolic name playerl.

The display task can accept two parameters, one indicating which configuration file to use and one indicating which monitor to display on. Here are the

lines:

task disp_eh displayl

args displayl netl xterm6:0.0
I 

Here the CTOS task disp..eh is the display program, and it is .referenced by t

symbolic name dis la 1. The two parameters are passed using the same ar s Y P Y P P g g lin

ii

The first parameter is the configuration file to use, and it is required. The secon

line is the actual display device to use. If the display device is omitted, the windo

will appear on the user's default device.

4.4 Petri Net Configuration Files

The Petri net configuration file is the mechanism used to provide the play

and display tasks with the configuration and task interconnections of the Petri ne

that they are to execute or display. The configuration files differ in content betwee

the player and display tasks, but their format is similar. In an effort to use existin

tools for the design and analysis of a distributed system, it is recommended that th

Petri nets be designed using GreatSPN, or another program such as Xpn that ca

generate the GreatSPN file format or this configuration file format directly. Th

configuration file begins with the GreatSPN net file, and additional configuratio

data for each place and transition is appended to the end. This approach wa

taken to allow the user to modify this additional data with a standard editor until 

customized design tool such as Xpn is fully developed and available. The file namin

convention used by this controller is that all player configuration files end in .pne

and that all display configuration files end in Asp.

4.4.1 Player File

The player configuration file provides the details of the executable net. It is i

this file that we specify the tape commands, enabling functions, and post function

for each transition. We also specify the owner task or every place referenced by 

transition in this net.
2

The configuration data begins with the line:

SUBNET task-name

This identifies the file as a player configuration file, and provides the symbolic name

of the task for reference. Following this header, there is a line for every place and

transition in the Petri net. The format for a place consists of:

PLACE local-name [LOCAL]I[REMOTE remote-name remote-owner]

A place with the LOCAL keyword is owned by this Petri net, and it is referenced

by all other tasks as local-name. A place with the REINIOTE keyword is owned by a

different Petri net, and corresponds to the place named remote-name in the playe

with the symbolic name remote-owner. Here is the format for a transition:

TRANS local name [TAPE command]

[[ENABLE-LOCAL function name action data-name]

I[ENABLE_REMOTE task-name action data-objects]]

[[POST-LOCAL function name action data-name]

I[POST_REMOTE task name action data objects]]

Transitions are always owned by the player that they appear in, and are not referenced by any other player tasks. Every transition may possess a tape command

requirement, which is denoted by the keyword TAPE and followed by the name

of the tape command. Every transition may possess either a local or a remote enabling function. Local enabling functions use the keyword ENABLE-LOCAL

and are followed by the local function name, an integer corresponding to the desired action, and a data name. A small data object manager exists in the player,

which handles the local variables. Remote enabling functions use the keyword ENABLE-REMOTE, and are followed by the task name that performs the function,

an integer indicating the desired action, and list of comma separated data objects

t
2!

Finally, every transition may possess either a local or a remote post function. The

post functions use the same format as the enabling functions, but use the keywords

POST-LOCAL and POST.REMOTE, respectively.

i

4.4.2 Enabling and Post Functions

The enabling and post functions are grouped into two classes: local and remote. The local functions are compiled into the player task itself, and are available

to all applications. These functions are executed and immediately completed upon

the firing of a transition.

The remote functions are independent of the controller, and require that some

other task is available to perform the action. When a post function needs to be

executed, the player sends a message to the appropriate servicer indicating that

the function has been called. The player then continues with its normal execution

sequence, leaving that particular transition in a .Firing state. Once the action is

completed, the servicez sends a message to the player indicating that the transition

can finish firing. This corresponds to the three transition firing phases discussed in

Section 2.2.

4.4.3 Display File

The display configuration file provides the relationship between nodes in the

display to nodes in the players. This allows the user to control the display content,

either to reduce complexity or stress certain behaviors. Each place in the display

Petri net is directly mapped to a place in a player Petri net. Transitions in the

display are either mapped to a single transition or a pair of transitions. When

two transitions are specified in the mapping, the firing of the first transition in the

Iplayer starts the firing of the transition in the display. The transition's symbol is

highlighted in the display while the transition is firing. When the second transition
of the pair completes its firing, the transition in the display completes as well. Th

allows a subnet of the actual player Petri net to be represented as a single transiti

in the display. The configuration data for a display file starts with the line:

DISPLAY task name primary player

This identifies the Me as a display configuration file, and includes the symbol

task name for this display and its primary player. The primary player indicat

which player Petri net, if any, should be the recipient of the user runtime comman

entered in this display that affect a single player. The format of a place consists o

PLACE local name remote-name remote-owner

The local-name is the name of the place that is displayed. The remote-name is th

name of the place in the player Petri net which we want to display. The remote own

is the task name of the player owning the remote place. The format of a transitio

is:

TRANS local name [SINGLE remote name remote owner]

([DOUBLE start-name start owner end-name end-owner

SINGLE is used when there is a direct mapping for the transition, while DOUBL

is used when start firing corresponds to one transition and stop firing correspond

to a different transition, as discussed above.

4.5 User Interface

M The user interface is implemented in the display Petri nets, and allows the use

to control not only display features but the actual execution of the underlying Pet

net. This interaction is provided by a combination of mouse and keyboard action

1 
Table 4.1: Display Commands

Cause Effect

Arrow Keys Shift the Petri net in the direction of the arrow.

<, > Scale the size of the Petri net down or up.

T,t Toggle the tags on the nodes on or off.

R,r Redraw the Petri net.

0,1, — ,8,9 Toggle the enabling of the different display layers

on or off. (Every element appears in layer 0)

4.5.1 Display Control

The user can manipulate the display in a number of ways for more efficien

viewing of the application. These features are accessed through the keyboard, an

are described in Table 4.1.

4.5.2 Player Control

The user can directly affect the execution of the underlying Petri net throug

the display. These actions are accessed through both the keyboard and the mouse

Table 4.2 describes the available commands.

4.6 Summary

This controller offers a simple, user friendly method of constructing and executing a distributed application. The interface to the external functions provide

a flexible mechanism that will satisfy the needs of future applications of this con

troller. The user interface is also extremely flexible, both in terms of the actua

display content and the display options.

t
Table 4.2: Player Commands

Cause J Effect

S Set the entire application into single-step mode.

An enabled transition will only fire when the

user clicks on it with the mouse pointer.

s Set the primary player for this display

(as indicated in the display configuration file)

into single-step mode. Other players are unaffected.

C Set the entire applic n.: ion into continuous mode,

where enabled transitions will fire as fast as

possible.

C Set the primary player for this display

(as indicated in the display configuration file)

into continuous mode. Other players are unaffected.

Selecting a Fire the transition if it is enabled and the

transition player is in single-step mode.

by mouse

Selecting a Left Button: Add a token to the place.

place Middle Button: Prompts user for new token quantity.

by mouse Right Button: Subtract a token from the place.

Q,q I Quit the application. User is prompted to verify.
CHAPTER 5 

IMPLEMENTATION VS. THEORY

5.1 Introduction

Now that the controller has been presented, it is important to verify t

the implementation maintains the desirable properties of Petri nets. There are t

P

issues to be faced: 1) can a distributed Petri net be correctly analyzed with t

existing tools; and 2) does the execution algorithm affect the properties of the n

5.2 Analysis of Distributed Petri Nets

Ideally we would like to be able to analyze each Petri net in isolation, a

from that infer'the properties of the distributed system as a whole. If we can ver

that the coordination structure maintains these properties, we can then develop -

analyze each net independently.

This approach of analyzing the individual components to determine the glob

i properties can be viewed as a synthesis problem. Can we begin with a single Pe

net, and synthesize other connected Petri nets in such a fashion as to maintain t

desired properties? If so, then the individual Petri nets in this connected structu

can be constructed utilizing these synthesis techniques, and it can be shown th

the global properties are unaffected.

This problem can be solved with a top-down synthesis technique, where 

aggregate model is repeatedly refined [21). This technique consists of refining 

y

single transition with a well-formed block, shown in Figure 5.1. This transiti

must not be 2-enabled (the number of tokens in its input places is only sufficie

for a sing'-- firing), and it is replaced with a well-formed block with these thr

conditions:

31
4

Figure 5.1: A Well-Formed Block

• The associated Petri net is live,

• The input transition to the block is only enabled when the associated net is

idle,

• The input transition is the only transition enabled by tae initial marking o

the associated net.

Under theca conditions, the liveness and boundedness of the overall net is preserved

The task here is to create a coordination structure for communication between two

nets.

The coordination structure presented earlier does indeed meet the condition

for this synthesis technique.

• The coordination structure itself is live and bounded, and one of the previously

discussed analysis tools can be used to verify whether the remainder of the
3

Petri net is live or not.

• The semaphore S ensures that the input transition begin is enabled only when 

the Petri net is idle.

• The use of places ready and S act to enable only begin under the initia

marking. The initial marking of the remainder of the Petri net should not

enable any other transitions.

Therefore, this coordination structure allows the isolated Petri nets to be verified

as live and bounded independently of the other nets, and maintain those properties

system wide.

There are a number of coordination structures that could be developed, but

care must be taken to insure that they are valid. The coordination structure that was

proposed by Wang [22] [25] in his development of the Petri Net Transducer contains

a subtle error. This original coordination structure, along with the current version

and a simplified implementation are shown in Figure 5.2. The original structure

contained two semaphores, SI and SO. This mechanism was chosen to speed the

execution of sequential requests. In theory, once an operation was completed, it

could be communicating the results to the calling Petri net while another action was

begun. However, this arrangement does not necessarily notify the correct transition

of the completion of an operation, as the following scenario demonstrates.

Two separate begin - end pairs wish to request an action from a single Petri

net. The input semaphore SI correctly allows only one of the begin transitions to

i fire. Once the first action is complete, transition finish will fire. This restores the

input semaphore, and puts a token in place O. This is where the problem occurs.

The second begin transition is now enabled and can fire. If it fires before the first

end transition does, there will be a token in both in-progress places. This means

that both end transitions are now enabled, and that either one could fire. If the first
end fires, then there is no problem. However, it is possible for the second end to 

first, and this is a violation of the correct net structure, as the firing of the seco

end should correspond to the completion of the second operation, which is stil

progress. This type of behavior is not only incorrect, but can be dangerous in a r

system such as the CIRSSE testbed, where the controller is operating physic

powerful and quick manipulators.

There are other possible valid coordination structures, as stated above. O

such structure is shown at the bottom of Figure 5.2. This is a simplified (in ter

of number of transitions and places) version of the current coordination structu

It removes a layer of transitions and places from the connection, but does not 

fer the intuitive structure of the current implementation. Future work includes t

development of a coordination structure that allows a Petri net to perform para

operations, while still maintaining the ability to analyze the net in isolation

parallel implementation can greatly enhance the utilization of the underlying ha

ware, and reduce the time necessary to complete some global task. A good examp

occurs in the motion coordinator, where it would be desirable to allow both man

ulators to move simultaneously, which is not possible with the current coordinat

structure. 

'^ 5.3 Execution Algorithm 

It has been shown that a distributed Petri net maintains the desirable pro

erties of a single net. Therefore, we wish to examine the behavior of the actu

execution algorithm in reference to the properties of Petri nets. It will be show

E 

that the chosen algorithm does not fully uphold the property of fairness, as well 

demonstrate that fairness is not strictly necessary for a Petri net controller. 

The execution algorithm consists of randomly selecting a transition to exam

ine, and firing it if enabled. Otherwise, progress linearly through the transition li
Current

Original

I 

i

begin in—progress end

begin in progress end

begin in—progress and

i Simplified

ready x avail >` done

Figure 5.2: A Coordination Structure Comparison

I
36

Figure 5.3: An Unfair Example

checking each transition until one can be feed. The case of concern is .shown in

Figure 5.3, where two transitions are enabled by the choice place ready. Suppose

that the transition starved occurs immediately after transition stuffed in the internal data structure for the controller. Both of these transitions are enabled when

there is a token in ready. Following the execution algorithm, a random transition

is selected for examination. Since stuffed is always enabled when starved is, and

it occurs immediately before starved in the data structure, it will be fired first
unless starved is selected directly by the first random choice. This can be sign

icant if the remainder of the net has a large number of transitions. Taken to 

extreme, if only these two transitions are enabled in a large net with thousands 

transitions, then stuffed will be fired thousands of times more often than starve

Fortunately, this behavior is very uncommon in controller applications. Due to t

distributed nature of many systems, the individual Petri nets tend to be small a

manageable. Secondly, very few control algorithms have a true choice place. T

common transitions will typically have an enabling function or tape requirement 

control the final selection of which transition to fire.

5.4 Summary

Through the use of a consistent interconnection scheme, distributed Petri n

can be analyzed in isolation, and provide information about the system as a who

Additionally, the implementation presented here maintains all of the desirable pro

erties of Petri nets that are relevant to controller applications.
CHAPTER 6

CASE STUDY: THE CIRSSE TESTBED

6.1 Introduction 

This chapter describes the architecture of the CIRSSE dual arm robotic testbe

and presents two case studies demonstrating the integration of multiple subsystem

through the use of this controller.

6.2 The Dual Arm Robotic Testbed

The Theory of Intelligent Machines (18] (20] presents a hierarchical structur

for the organization of an autonomous robotic systein. This hierarchy is based on

the principle of Increasing Precision with Decreasing Intelligence. There are thre

distinct levels to this hierarchy: the organization level which provides for global task

planning; the coordination level which serves to integrate the physical capabilities of

the system and decompose global plans into a sequence of lower-level operations; an

the execution level which consists of the actual hardware and low level functiona

capabilities. 

This structure has found an implementation in the CIRSSE dual arm robotic

testbed (9] (26]. The execution level is segmented into two subsystems: the Motion

Control System (MCS) and the Vision Services System (VSS). MCS is responsible

n ,.

for interfacing with the low level capabilities of the manipulators. The hardware 

consists of two 6 degree-of-freedom PUNIA robotic arms each mounted on a 3 degreeof-freedom cart which moves along a common linear track. This provides for a tota

of 18 degrees-of-freedom. The MCS software is executed on a dedicated `. ,",WE cage

running the VxWorks operating system. VSS is responsible for interfacing to the

cameras and image processing hardware. Five cameras may be used for stereo or

38

--- , 
i

f

r

1.

i.

f

39

mono vision purposes; two are mounted to the ceiling, two are mounted on the endeffector of one robot, and one which is not yet dedicated. A laser scanner is available

for pointing or pattern projection. These devices are connected to a Datacube image

processing system residing in a VME cage.

The coordination level is of primary interest to this thesis, as the Petri net

controller resides here. The coordination level receives commands from the organization level, and decomposes them into portions manageable at the execution level

The coordination level contains two interior levels, consisting of a dispatcher and a

number of coordinators.

Intelligent I Organization Level

Organizer

Dispatcher

Coordination Level

Vision Motion I I Other

Coordinator Coordinator • • • • Coordinator

Vision Motion .. , , Other

Servicer Servicer Servicer

Execution bevel

Mazupulator I

.... I Other

Hardware Hardware

Figure 6.1: The Hierarchy of an Intelligent Machine

The hierarchical configuration of an intelligent machine is shown in Figure 6.1,

where it is apparent that the coordination level is also arranged hierarchically. The

Vision

Hardware
.

40

dispatcher and coordinators are all player tasks in the controller. The coordinators

-represent the capabilities of their particular subsystem, while the dispatcher serves

to decompose high-level commands into lower-level commands suitable for the individual coordinators. Another feature to note is that the coordinators are designed

=to process only one action at a time from the dispatcher. This does not preclude a

,particular coordinator from performing concurrent operations in order to process a

particular command.

6.3 Case 0: Camera Calibration

Before the testbed can be fully utilized, the ceiling cameras must be calibrated.

The algorithm for this process is simple, yet it makes full use of the key concepts

developed for the controller. A light source is placed in the open gripper of one of

the manipulators. The manipulator grasps the light, and moves it to a fixed number

of positions in the viewing region of the ceiling cameras. At each position the vision

system determines the position of the light in terms of camera coordinates, while the

motion system determines the position of the light in terms of world coordinates.

These values are stored in a file, and can be accessed as needed by the various

components. Once all of the data points have been obtained, the camera calibration

parameters are calcuiated, thereby completing the camera calibration process.

This distributed system has been analyzed using the Petri net tool GreatSPN

and the method presented in Section 5.2, and was found to be live and bounded.

Each Petri net was analyzed in isolation, and their individual properties of liveness and boundedness can be applied to the system as a whole due to the use of

coordination structures for inter-net communication.

6.3.1 Dispatcher

The dispatcher serves to parse high-level commands into lower-level commands
row

WLPa

r 

I 

Mum m1cm

.plibnre

S"imneea init csLb Qec_aur reo4Po^

m6ot loop coat por<^raiil

I

robot

FALvot

taGb done ^ ata / t4ve^os

atzb ales 1 p~ddte ado-rt'^''

Figure 6.2: Case 0: Dispatcher Display and Player

r

f

i^

s

I;

E
H1t

k

S

i

understandable by the individual coordinators. In this case, the dispatcher perfo

-.the overall algorithm, while the coordinators control their respective systems. 

display and player Petri nets for the dispatcher are shown in Figure 6.2, which 

the upper and lower Petri nets, respectively. Here you can gee that the Petri 

shown on the display is a slightly simplified version of the underlying net, omit

the communications details necessary for interfacing with the coordinators.

The command calibrate-camera is given to the dispatcher by placing a to

in the place calibrate. This enables the transition init-calib if the robot a

camera are available. The transition init_calib in the display represents the 

initialization transitions in the player, namely init_calib and initloop. Init_c

in the player executes the remote post function which opens the file contain

the calibration points. Initloop executes a local post, function which initializ

loop variable to the number of calibration points. The transitions dec-cntr a

read pos decrement the loop variable and load the next calibration point fr

the file, respectively. The transition move-robot corresponds to a coordina

structure which requests the motion coordinator to mcwe to the destination positi

This transition does not complete its fuing until the motion coordinator replies t

it is done. The net now splits into two parallel paths, demonstrating the abi

to perform concurrent operations. The transition find_pos is another coordinati

structure which requests the motion coordinator to find the exact location of 

robot, while savepos stores this value in a file. The transition find-spot i

coordination structure which requests the vision coordinator to locate the bright s

in the cameras field of view, and save-spot stores this value in a file. This process 

moving and storing location information is repeated a number of times correspond

to the loop variable. The transition pair loop-again and loop done perform 

actual looping action. An enabling function is attached to each transition, wh

checks the status of the looping variable. If the loop variable is now zero, th

M:
loop-done is enabled, otherwise loop-again is enabled. After all of the calibratio

data has been obtained, the loop is exited and calib-calcs fires. A post functio

performs the calculation of the camera calibration parameters, and the resource

are returned.

6.3.2 Motion Coordinator

The coordinators reflect the capabilities of their particular subsystem, hidin

many of the details from the dispatcher. The motion coordinator is very simple fo

Y

this case, possessing only two actions callable by the dispatcher. The display an

player Petri nets are shown in Figure 6.3, and you can see that both Petri nets ar

identical. The transition do- ind pos queries the motion servicer for the position o

the manipulator used for the calibration. The other transition do-move activate

the portion of the net that is responsible for moving the robot. Two paths exis

within this action, .depending upon whether a path plan already exists or not. 

the path already exists (and for this case it does, as the dispatcher is simply ex

ecuting moves to_preplanned robot joint positions) we can proceed to moving th

manipulator via validate path and movelnanip. Otherwise, the motion coord

nator would fire plan path to ,generate a path, and then movelnanip to mov

the manipulator.

6.3.3 Vision Coordinator

The vision coordinator for this case represents the minimum Petri net structur

for a coordinator. The display and player Petri nets are shown in Figure 6.4, an

like the motion coordinator, they are identical. There is only one action callable b

the dispatcher, and is activated by transition do-find-spot which locates the ligh

spot in the camera's field of view and stores its position in the DOM.

L
mc-9 Mc—I Mc.O mc-SO

MC,laady mc.A 

MC.Km MC &Qbbe MAIM

s'0

s r 

dolind,.Poa

NJ ^ "v

m9.^mOVa do^ova — "'P

pian,pads

mc_x MCi MC_O MC-SO

MC^dy M^dos

MC slut MC avedwe MCJiwA

&^^

va1(dsta^Mh

vww

to Uwe do-move II1OY0^p 

Figure 6.3: Case 0: Motion Coordinator Display and Player
rego,

vc—St vC ( yr n --

vC_I vc-I yr n

Figure 6.4: Case 0: Vision Coordinator Display and player
6.4 Case 3: Strut Insertion

This cane considers a more difficult task which is more representative of 

typical use of the robotic platform. A partially completed strut and node triang

is placed on a table, and the task at hand is the insertion of the third strut 

complete the triangle. This task is significantly more complicated than the came

calibration, with about an order of magnitude more transitions and places. Th

problem is shown in Figure 6.5.

This case study has not been fully executed yet, as the functional code for th

path planner is currently under development. However, the controller is being use

for the testing and debugging of those modules still under construction.

6.4.3 Dispatcher 

The dispatcher for this application makes good use of the controllers ability t

perform parallel operations, as well as to coordinate the sequencing of asynchronou

events. Due to the size and complexity of this net a transition by transition expla

nation will not be given. Rather, a verbal overview of the dispatcher's actions wil

be presented. The Petri nets for the display and player tasks are shown in Figure

6.6 and 6.7, respectively.

The triangle completion begins by initializing the vision system in parallel with

the manipulator and path planning systems. Note that the path planner canno

begin initialization until the robot is initialized, since it requires knowledge of the

position of the robot and must move it to the home position if it is not already

there. 

The vision system must now locate the partially completed triangle, and cal

culate the approximate position of the first uncompleted node. The path planner 

plans a path to this node, and the motion system moves the manipulator to it

While the arm is in motion, the path planner is already calculating the path to th
L

Figure 6.5: Case Study 1: Strut Insertion
Figure 6.6: Case 1: Dispatcher Display
r

r

r

r

4

Vision Motion Par Planner

Coordiraior Coordi u!c: Coordinator

Figure 6.7: Case 1: Dispatcher Player; dote the Complexity versus

the Dispatcher Display Petri Net
50

second node. The camera's on the arm now locate the node more accurately, and

the arm moves to the second node where its location is refined as well.

While the location of the second node is being refined, the path planner is

calculating a path to the rack containing extra struts. Once the arm is available,

it moves to the rack and picks up a strut. During this time, the path planner is

first calculating a path to insert the strut in the uncompleted triangle, and then to

move to some final safe position. The arm moves to an approach position over the

triangle, and inserts the strut.

T',.e triangle is now complete, so the robot moves to the sate position, and the

three subsystems are shut down.

The dispatcher for this case provides a good example of why such a flexible

display system was developed. The ?lgorithm given above ;s clear in the display

Petri net, where each action to be performed by the coordinators is represented

by a single transition. The coordination structures in the player Petri net make it

very difficult to understand, with a large number of arcs crossing each other as well

as the individual places and transitions. The coordination structures for the three

coordinators are indicated in the boxed regions at the bottom of the figure. The

upper boxes labeled Arb correspond to the Arbitration portion of the structures,

where access to the particular coordinator is controlled. The lower boxes labeled

Com correspond to the different commands offered by each coordinator. Note that

the tags for the places and transitions are not shown in the player Petri net, since

they were illegible.

6.4.2 Motion Coordinator

The player Petri net for the motion coordinator is shown in Figure 6.3, and it

contains seven operations. The transiticns do-init..robet and do-shutdown-robot
if

it

Er

51

are used to initialize and shutdown the robot. The transition do- ind_pos determines the exact position of the robot, as known by sensors on the manipulator itself.

The last four transitions per`orm different types of move commands, ranging from

a general move to a specific sequence such as inserting a strut into a node pair.

6.4.3 Vision Coordinator

The player Petri net for the vision coordinator is shown in Figure 6.9, and it

performs five operations. Similarly to the motion coordinator, two of these transitions, do-init-camera and do-shutdown-camera, are used to initialize and

shutdown the camera system. The transitions do-find-spot and do-find-object

locate the bright spots and a particular object, respectively. The last transition,

do-refine-pose, more accurately determines the location of a node through the use

of the arm cameras. This requires that the node must be located relative to the arm

cameras, and that the position of the cameras be known. The location of the node

in world coordinates is determined after these two parallel operations complete.

6.4.4 Path Planner Coordinator

The path planner coordinator is slightly different from the other coordinators

in that it has no direct execution level counterpart. The path planner is strictly a

software module, and is not responsible for interfacing to any hardware.

The player Petri net for the path planner is shown in Figure 6.10, and it consists of five operations. Two transitions, doinit-PP and do-shutdown-PP, are

responsible for the initialization and shutdown of the path planner. The remaining transitions calculate different kinds of paths, ranging from a simple start-to-end

point path, to specific paths such as a current position to approach position for

insertion path.
I.. .

5

MC_sI MCI MC-0 MC_So

MC-.=4 MCd

MC_scart MC_a d ble MC cnish

nqjWLmbot

do

J__ dc_auat_sCUt

... -_TIC`_ do-'i'gC" 

Figure 6.8: Case 1: Motion Coordinator Player
_

m

vc sc vc_I vc_o vc so

mgcode cmd =&-M"

Figure 6.9: Case 1> Vision Coordinator Player
o

PC-So

^ 

m,

''--__``

V

dsh

Figure 6.10: Case 1: Path Planner Coordinator Player
S

r 

i

6.5 S ummary

The capabilities of this controller haw been demonstrated through two case

studies on the CIRSSE dual arm robotic testbed. Case study 0 hai been imple

mented and executed, successfully providing a method for the simple control ove

calibrating the stereo ceiling cameras. The functional code for case study 1 is still 

under development, and the controller is providing a userFpdly method of tesLing

V,

the individual ocomponents as they are constructed. ,. 

- r

i

i

r

I ^.i
CHAPTER 7

CONCLUSIONS AND FUTURE RESEARCH

E'.

U

17..1 Conclusions

;s

This thesis described the need for a tool which could provide some means 

modeling, integrating and controlling an application. A Petri net based control

was presented as a solution, and two case studies demonstrated that it could sati

these criteria for a distributed heterogeneous hierarchical system. Its main streng

are:

• A controller algori-tithm based on Petri nets which allows the system to be ma

ematically analyzed for performance and desirable properties such as livene

boundedness, etc.

e Straightforward design and interconnectiv;ty of the individual Petri nets.

e Compatible with CTOS

— Fully integrated with the Execution-level services provided by MCS a

VSS.

— Easily configurable for distributed and heterogeneous applications.

e Demonstrated parallelism of the CIRSSE 'testbed

— Modeled and controlled a hierarchical configuration.

— Provided for the operation of a multiproccssor system.

e A user friendly graphical interface for the monitoring and control of each Pe

net.

56
57 

• Highly configurable displays for the more efficient representation of the underlying Petri net control structure.

7.2 Future Research and Modifications

a Expand the firing of transitions to record performance data. This information

can be used to enhance the analysis of the net with one of the previously

mentioned tools. Remember, those modeling tools require that the user enter

his best guess for timing parameters. Initial estimates can be made and then

enhanced as the system is implemented for more refined modeling.

o Supplement keyboard commands with equivalent on-screen X-window gadgets.

Many operations, such as scrolling the display, would be more efficient with a

mouse and gadget interface.

• Construct an event handler task for editing and sending Petri Net Transducer

tapes to the player tasks.

• Provide for outlining or otherwise marling sections of the Petri net in the

displays. This would allow for visible segmentation of associated groups within

the Petri net.

• Develop or enhance existing Petri net design tools such as Xpn or CreatSPN

to fully support the creation and modification of the player and display coafiguration files.

W.
LITERATURE CITED

1.

[1] Al-Jaar, R.Y., Desrochers, A.A., "Petri Nets in Automation and

Manufacturing", Advances in Automation and Robotics, (G.N. Saridis, ed.),

vol. 2, pp. 153-225, JAI Press, Greenwich, CT, 1990.

[2] Bjanes, A., "A Distributed Petri Net Controller for a Dual Arm Testbed",

Master's Thesis, Electrical, Computer, and Systems Engineering Department

Rensselaer Polytechnic Institute, May 1991.

[3] Chiola, G., "GreatSPN 1.5 Software Architecture", University of Torino, July

1990.

[4] Ciardo, G., "Manual for the SPNP Package Version 3.0", Duke University,

June 1990.

[12] Murata, T., "Petri Nets: Properties, Analysis and Application", Proceedings

of the IEEE, vol. 77, no.4, pp. 541-580, April 1989.

[13] Peck, J., "GreatSPN2SPNP User's Manual", CIRSSE Unix Man Pages,

Pensselaer Polytechnic Institute, August 1990.

I5] Crockett, D., "Manufacturing Workstation Control Using Petri Nets",

Master's Thesis, Electrical, Computer, and Systems Engineering Department

Rensselaer Polytechnic Institute, August 1986.

[6] Fieldhouse, K., Holt, K., Lefebvre, D., Murphy, S., Swift, D., 'Watson, J.,

'Lecture Materials for the CTOS/MCS Introductory Course", CIRSSE

Report 97, Rensselaer Polytechnic Institute, July 1991.

[7] Freedman, P., "Time, Petri Nets, and Robotics", IEEE Transactions on

Robotics and Automation, vol. 7, no. 4, pp. 417-433, Aug 1951.

[8] Kim, J., "Xpn: Petri Net GUI", Rensselaer Polytechnic Institute, Oct. 1991.

[9] Lefebvre, D.R., Saridis, G.N., "A Computer Architecture for Intelligent

Machines", CIRSSE Report 108, Rensselaer Polytechnic Institute, 1991.

x

[10] Marsan, A., "Stochastic Petri Nets: An Elementary Introduction", Advances

m in Petri Nets 1989 (G. Rozeeberg, ed.), pp. 1-29, Springer-Verlag, 1989.

[11] Mittman, M., "TokenPasser: A Petri Net Specification Tool", Master's

Thesis, Electrical, Computer, and Systems Engineering Department,

Rensselaer Polytechnic Institute, May 1991.

58
59

[14) Peterson, J.L., "Petri Net Theory and the Modeling of Systems",

Prentice-Hall International, Englewood Ciiffs, NJ, 1981.

[15) Robinson, J., "Performance Analysis :)f a Robotic Testbe3 Control

Architecture", Master's Thesis, Electrical, Computer, and Systems

Engineering Department, Rensselaer Polytechnic Institute, December 1989.

[16] Rudolph, D., "Petri Net-Based Contro'- of a Flexible Manufacturing System",

Master's Thesis, Electrical, Computer, and Systems Engineering Department,

Rensselaer Polytechnic Institute, May 1989.

[171 Saridis, G.N., Stephanou, H.E., "A Hierarchical Approach to the Control of A

Prosthetic Arm", IEEE Trans. Sys., Nlan and Cyber., vol. 7, pp. 407.420,

1977.

[18] Saridis, G.N , "Architectures for Inteodigent Machines", CIRSSE Report 96,

Rensselaer Polytechnic Institute, Aug 199'..

[19] Saridis, G.N., "Intelligent Machines: Distributed vs. Hierarchical

Intelligence", Proc. IFAC11MAC Int. Symp. on Distrib. latelligence Systems

(Varna. Bulgaria), pp. 34-39, 1988.

[2U] Saridis, G.N., "Tnward the ReaUration of Intelligent Controls", Proceedings of

the IEEE, vol. 67, no. 8, 1979.

[21] Valette, R., "Analysis of Petri Nets by Stepwise Refinement", Journal of

Computer Systems Science, vol. 18, pp 35-46, 1979.

[221 Wang, F., "X Coordination Theory for Intelligent Machines" Doctoral Thesis,

Electrical, Computer, and Systems EnginetiAag Department, Rensselaer

Polytechnic Institute, May 1990.

[23] Wang, F., Saridis, G.N., "A Formal Model for Coordination of Intelligent

Machines using Petri 'vets- , Proc 3rd IEEE Int. Intell. Control Symp.

(Arlington, VA), 1988.

[241 Wang, F., Kyriakopouk^;, K.J., Tsolkas, A., Saridis, G.N., "A Petri-Net

Coordination Model of Intelligent Mobile Robots", CIRSSE Report 50,

Rensselaer Polytechnic Institute, Jan. 1990.

[25] Wang, F., Saridis, G.N., "Structural Formulation of Plan Generation for

Intelligent Machines", CIRSSE Report 40, Rensselaer Polytechnic Institute,

Sept. 1991.

[261 Watson III, J.F., Lefebvre, D.R., Desrochers, A.A., Murphy, S.H., Fieldhouse,

K.R., "Testbed for Cooperative Robotic Manipulators", in Intelligent Robotic

Systems For Spare Exploration , (A.A. Desrochers, e(L), pp. 1-38, Kluwer

Academic Press, Norwell, MA, 1992.
APPENDIX A

Local Enabling and Post Functions

The local enabling and post functions were initially implemented to provide a means

of performing deterministic looping behavior. They have been expanded to include

any functions that are relatively small, generic to many applications, and linked to

the player code.

A.1 Enabling Functions

done action data name

Use: To check the state of a local variable.

Returns: TRUE if the contents of data_uame - 0,

FALSE otherwise.

This behavior holds when action - 1,

if action = -1 the logic is reversed.

DOM_done action data_name

Use: To r;:^_k the state of a variable in the DOM.

Returns: '.WE if the contents of data_name - 0,

FALSE otherwise.

This behavior holds when action = 1,

if action = -1 the logic is reversed.

DOM_bool action data-name

Use: To check the state of a variable in the DOM.

Returns: FALSE if the contents of data_uame = 0,

TRUE otherwise.

60
r 6

This behavior holds when action - 1,

if action = -1 the logic is reversed.

A.2 Post Functions

initialize action data_name

Use: To initialize a local variable to a fixed value.

Operation: Sets the contents of data_name to action.

live_init action data_name

Use: To initialize a local variable to a runtime value.

Operation: Prompts the user to enter the desired value,

and sets the variable data_name.

decrement action data_name

Use: To decrement a local variable by a fixed value.

Operation: Subtracts action from the contents of data name.

increment action data_name

Use: To increment a local variable by a fixed value.

Operation: Adds action to the contents of data_name.

renameObjs action data_name

Use: To rename a variable in the DOM.

Operation: Here data name is the comma delimited source

and destination variable names.

dupObjs action data_name
Use: To duplicate a variable in the DOM.

Operation: Here data name is the comma delimited source

and destination variable names.

alive action data_uame

Use: To print a flag when a transition fires.

Operation: Prints the string "alive: " folloued by

the integer value of action.

I .
APPENDIX B

Header Files

iB.1 Globa!_var.h -- The Global Variables

/* CTOS variables */

jTID_TYPB globTid;

i /* X-display variables *!

Display *display;

Window *window;

GC gc;

( XFontStruct *font [4] , *act_font;

{ int screen_num;

` char display_name[100];

/* Size variables */

int diameter, radius, radins2;

float scale, offset_x, offset-y;

unsigned int line width;

/* user options *I

int molt, tags on, rates_on, visible_layer = Oxffff;

f int mode = SINGLE-STEP;

+ TID_TYPE playTid;

1-

/* net objects */:

struct Place *place;

struct Trans *trans;

strnct MPar *npar;

atract BPar *rpar;

int num_mp, num_pl, num_rp, num_tr, num_gr, num_cs;

. char *uet_name

t

/* tape variables */

? stract tape-node *head, *tail;

1

struct tape- entry tape table q

{{1,11MOVE"},

{2,11GAASP"},

{3,"LOOK11}.

{4,11STOP"}.

{5,"CAL_VIS"}

63
.

B.2 GlobaLvar.p — The Global Variable Prototypes

/* CTOS variables */

extern TID_TYFE globTid;

/* X-display variables */

#include <Xil/Xlib.h>

extern Display *display;

extern Window *window;

extern GC gc;

extern XFontStruct *foat[4]. *act_font;

extern int screen_num;

extern char display_nameL100];

/* Size variables */

extern int diameter, radius, radius2;

extern float scale, offset -Y, offset_y;

extern unsigned int line width;

/* user options */

extern int malt, tags -on, rates-on, visible_layer;

extern int mode;

extern TID_TYPE playTid;

/* net objects */

extern struct Place *place;

extern strict Trans *trans;

extern strict MPar *mpar;

extern struct RPar *rpar;

extern int num m num 1 num nun tr nnm num_cs

extern char *net name

/* tape variables */

extern strict tape-node *head, *tail; 

extern strict tape-entry tape_table Q ; 

B.3 Global_defh — The Global Definitions

FILE: f:lobal_def.h

*

/* general defines *i

#define MARLINE 255 

/* modes of operation */
6

#define CONTINUOUS 1

*define SINGLE-STEP 2

/* transition ID's *!

l

#define EXP 0

*define IMM 1

#define DET 127

#define DEFAULT 200

/* arc ID's */

I#define INPARC 0

*define OUTARC 1

#define INHARC 2

( /* type of config file */

#define CF_PNET (1) /* config file for subnet player */

I #define CF DISP (2) /* config file for subnet display */

i

/* type of net node */

#define PLACE_KODE (0)

#define TRANS_NODE (1)

/* graphics defines */

#define PIZ_PER_IH 60

#def ine SCALE 1

*define DIAMETER 23

#define INTO PIX(a) (int)((a)*PIZ_PER_IN)

*define X_IN_TO_PIZ(a) (int)(IN_TO_FIX(a)*scale+IN_TO_PIX(offset z))

*define Y_IN_TO_PIX(a) (int)(IN_TO_PIX(a) *scale+IN_TO_PIX(offset_y))

#define ANG (1.4_PI/12)

#define max(a.b)-:(((a)>(b))? a:b) 

*define ERASE 0

*define DRAW 1

*define INVERT 2

*define S 0.4

*define M 0.5

#define L 0.7

/* net elements */

#include <ctos.h>

f typedef unsigned int UIHT

typedef unsigned short USHORT 

*define T_START 0x01

#define TEND 0x02

#define T_BOTH OxO3

typedef struct _upolst

{

TID_TYPE tid

USHORT num

USHORT which; /* start or end tiring of trans */

struct _upolst *next

i

}

1

r 7-
66

UPDATES

struct Arrowhead

{int x0,y0.xl,yl.x2,y2;

struct Arc-point

{int x.y;

float x_in, y_in;

struct Arc point *next;

struct Arc

{int x_start, y_start;

float x_start_in, y_start_in;

struct Arc-point *arc points;

int x_end. y_end;

float x_end_in, y_end_in;

int type;

int molt;

int place;

int layer;

struct Arrowhead *arrow;

struct Arc *next;

};

struct Place

{char *name;

VIAT id ;

int orig token;

int curr_token;

int x_loc, 7_10c;

float x_loc_in, y_loc_in;

int tag-z, tag-y;

float tag_x_in, tag_y_in;

int layer;

int locked;

int tid;

TID_TYPE owner

char *act_name;

UPDATES *update

struct Trans

{char *name;

char *act_name;

char *act_end_name;

VINT id ;

MIT end_id

float fire_rate;

int kind;

int orient;

int x_loc, y_loc;

float x_loc_in, y_loc_in;

int tag_x, tag-y;

float tag_x_ia, tag_y_in;

int rate_x, rata_y;

float rate_x_in, rate-y-in;

struct Arc *iup_arc;

struct Arc *out_arc;

struct Arc *inh_arc;
int layer;

int firing;

int tape_req;

int enable type;

int

( *enable_func)();

int enable action;

int enablevar;

char *enable data;

int post typo;

void (*post_fuac)O ;

TID_TYPE post tid;

int post-action;

int post var;

char *post data;

TID_TYPE owner ;

TID_TYPE end owner

UPDATES *update

struct HPar

{char *name;

int nwz_token ;

int tag-x. tag-y;

float tag_x_in, tag-y-in;

int layer;

};

struct RPar

{char *name;

float fire-rate;

iat tag_x. tag_y;

float tag_x_in, tag-y-in.;

iat layer;

};

/* struct for registering P h T */

typedef struct {

char *sym_name [64] ;

char *act name [64] ;

int type

int id ;

M. USHORT which; }

RZG_REKOTE

/* Tape stuff */

#define MAX_TAPE S

struct tape-node

{int id;

struct tape_node *next;

};

struct tape-entry

{int id;

char 

* ident_str;

};

IL

!^'` 
/* enable and post function stuff «/

#define F-1ONE 0

itdef ine F_LOCAL 1

#define F_REMGTE 2

#define REMOTE_POST_FUNC " send-post-mossage"

struct func_entry

{int (*func_ptr)();

char *ident_str;

#define OBJ_NAME_LENGTH 256

typedef struct

{

int infix

int action

char data_obj [OBJ NAME_LENGTH]

}

POST-DATA;

/* variable stuff */

#define MAX-VAR 200

struct var_entry

{int value;

char *ident_str;

};

/* macro definitions */

#define MARE_ID(tid.type.iudx) ( (((tid )«16) # Oxffff0000)

I (((type)«15) a 0x00008000) \

I ( ( indx) a 040007fff))

#define TID_FROM_ID(id) ( ((id) a 0xffff0000) >> 16 )

#define 'IYPE_FROM_ID(id) ( ((id) a 040008000) >> IS )

#define INDEX_FROM_ID(id) ( (id) a 0x00007fff }

#define ENCODE_BUTTON(b.id) ( (((b)«16) a Oxffff0000) \

1( (id) a Ox0000ffff))

#destine GET-BUTTON(id) ( ((id) a Oxffff0000) >> 16)

#define GET_INDEX(id) ( (id) a Ox0000ffff )

#define LEFT Ox00000001

#define RIGHT 0x00000002

#define UP040000004

#define DOWN Ox00000008

#define HORI_SHIFT(id) ( (((id) a LEFT) * -1) \

• (((id) a RIGHT) >> 1) )

#define VERT_SHIFT(id) ( ((((id) a UP) >> 2) * -1) \

• (((id) a DOWN) >> 3) )

#define SCALE-FACTOR 0.1

#define DEC -1
r

*define INC 1

BA msg.h — The Controller CTOS Messages

/* Messase commands */

#define MSG_COORD 11000

#define MSG -DRAW-WHOLE-NET MSG_COORD+1

#define MSG_SET_TOK MSG_COCRD+2

*define MSG_START_TRANS MSG_COORD+3

*define MSG-END-TRANS MSG_COORD+4

#def ine MSG-APP-TAPE MSG_COORD+S

*define MSG_INS_TAPE MSG_COORD+6

#define MSG _CLR_TAPE MSG_COORD+?

*define MSG-ABS-TAPE MSG_COORD+e

#define MSG-ADD-TOKEN MSG_COORD+9

#define MSG -SUB-TOKEN MSG_COORD+10

*define MSG_CHK_FIRE_TRANS MSv_COORD+11

*define MSG_TRANS_FIRED MSG_COORD+12

*define MSG_TRANS_DONE MSG_CCORD+13

/* Mouse Actions */

*define MSG_SELECT_TRANS MSG_COORD+20

*define MSG-SELECT-PLACE MSG_COORD+21

/* Keyboard Actions */

*def ine MSG_CHANGE_SCALE MSG_COORD+30

#def ine MSG_SHIFT_DISPLAY MSG_COORD+31

#define MSG-TOGGLE-TAGS MSG_COORD+32

#define MSG-SET-MODE MSG_COORD+33

#define MSG_VISIBLE MSG_COORD+34

#define MSG -SIT-ON-HANDS HEG_000RD+40

*define MSG -YOU-ARE MSG_COORD+51

#define MSG_INIT_DISPLAY MSG_COORD+52

*define MSG_INIT_PLAYER MSG_COORD+53

*define MSG_REGISTER_REMOTE MSG_COORD+54

#define MSG_CONFIRM_REMOTE MSG_COORD+SS

#define MSG_REGISTnR_UPDATE MSG_COORD+56

c

r

r

it
APPENDIX C

Player Software

CA makefile -- The Player Make&le

# Maketile for test of UNIX versicu of CTOS

INCI = /home/page/MCS/src/lib/bts.ib

INC? _ /home/page/NCS/src/lib/ms&Lib

INC3 = /home/page/NCS/src/lib/ctosShell

INC4 = /usr2/testbed/CIRSSE/installed/UNIX/h

INCS = /home/page/NCS /sry/lib/recLib

INC6 = /home/lefebvre/unix/ctcs/dcmLib

INC7 = /home/lefebvre/DEMOS/demol

CFLAGS = -0 -Wreturn-type -Nunused -Hsvitch -Ncomment -Nshadov

-wpointer-arith -DMAKE_SUN4 -I$(INC1) -I$(INC2) -I$(INC3)

-I$(INC4) -I$(INCS) -I$(IXC6) -I$(INC7) -DOS_b-NIT

BINDIR = /home/page/MCS/bin/sun4/

BTSLIB = $(BINDIR)btsErr.o $(BINDIR)btsSem.o $(3INDI1)btsGlobals.o

a(BIIDIR)msgLib.o $(BINDIR)msgBCNem.o

RECDIR = /hcs:e/page/MCS/bin/sun4/

# List of targets...

all : play-eh

E. I. Tasks...

play-eh: play_sh.o Xplay.o load_net.o tape.o msgs.o post_func.o \

enable: unc.o var_man.o

gcc $(CFLAGS) -o play-eh play_eh.o Xplay.o tape.a msgs.o \

post_func.o enable_func.o load_uet.o var_man.o $(RECDIR)recLib.o \

3(BTSLIB) $(BINDIR)ctosShell.o \

-L/home/lelebvre/DEMOS/demos -L/home/lefebvre/unix/ctos/domLib \

-lcoord -ldom -lm

play_eh.o: play_eh.c Global var.h Global_def.h

gcc -c $(CFLAGS) play_eh.c -o play_eh.o

Xplay.o: Xplay.c Global_det.h

Sec -c $(CFLAGS) Xplay.c -o Xplay.o

load_net.o: load_net.c Global_del.h

gcc -c $(CFLAGS) load_net.c -o load_net.o

tape.o: tape.c Global_def.h

gcc -c $(CFLAGS) tape.c -o tape.o

post- func.o: post_func.c Global_def.h

gcc -c $(CFLAGS) post_func.c -o post_func.o

70

#
71

eaable_tuac.o; enable_tunc.c Global_dei.h

gcc -c $(CFLAGS) enable_func.c -o enable_tunc.o 

msgs.o: msgs.c Global_det.h

gcc -c $(CFLAGS) msgs.c -o msgs.o

var_man.o: var_man.c Global_dei.h

gcc -c $(CFLAGS) var_man.c -o var_man.o

C.2 play_eh.c -- The Player Event Handler

File: play_eh.c

Purpose: "Petri Not Player" evr:nt handler task executes subset

Author: Joe Peck

revised: Don Lefebvre

Revised: 19 Aug'91

------------------------------------- include files --------------------*/

*include <Xil/Xlib.h>

*include <X11/Xutil.h>

*include <111/Xos.h>

*include <Xii/Xatom.h>

*include <stdio.h>

*include <ctos.h>

*include <btsLib.h>

*include "recLib.h"

*include "msg.h"...

*include "Global_def.h'-

*include "Global_var.h'-

*include "Xplay.p"

/*------------------ ----- _----- definitions -- -- -- */

/*------------------------------------- variables

in% go s FALSE;

char root_name[401;

char *myBame ;

char config_file [MAXLIBE]

/* --------- -----------_ -------- function prototypes ----------*/

j STATUS load-not (char *net_config_file, int type)

STATUS register_remote () ;

STATUS confirm-remote (TID_TYPE req. AEG-REMOTE *ps)

STATUS save remote (REG_REMOTE *ps)

STATUS save-update (MSG-TYPE *m)

STATUS initial marking () ;

void printPTinfo () ;

int cutAres (struct Arc *p)

int find-place (char *same) ;

int find-trans (char *name) ;

MyTask(play_eh)

i

L
/#r###rrr##r#r#rrrr########################################*###################

play-eh - subnet player for Petri let

` SYM80LIC TAME: (used to contignrs net)

RETURNS: 0 indicating processing complete

PARAMETERS: TID_TYPE myTid -task id of event handler

MSG-TYPE *nag - pointer to received message

iat play-eh (TID_TYPE myTid, MSG-TYPE *nag) 

int t_num

switch (mag->commaad)

{

case MSG_TASK_ARGS:

strcpy ( root_name, ( char *)mag->data);

break;

case MSG_PINIT: 

setRunTime ( 120) *!

/* read display config file */

globTid = myTid;

myName = msgXyTaskName (myTid)

aprintf ( config file, " %sys", dir_name, myffame) */ 

if (load-not (rootmame, CF_PNET) _= ERROR)

reclafo (myTid, "Unabl e, to load config file 'ys.pnet "',

root name); 

msgApplicationExit (myTid)

break

}

/* recInfo (myTid, "PLAY: Loaded not Is.past'W'. root-name); *!

break 

case MSG_AINIT:

register remote O

break

case MSG_AEXEC:

initial marking () ; 

go a TRUE; 

/* printPTinfo

break 

case MSG_REGISTER_REMOTE:

confirm remote (msg->source, 

(REG_REMOTE *) mag->data)

break; 

case MSG_CONFIRM _REMOTE:
save: emott ( ( REG_REMDTE *) msg->data)

break;

case MSG_REGIS ` eER_UPDATE:

save-update (msg)

break;

case MSG-APP-TAPE:

reclnfo (myTid, "PLAY: Received APP_TAPE\n");

append_tape((int)msb->data);

break;

case MSG_INS_TAPE:

recInfo (myTid, "PLAY: Received INS_TAPE\n"'4;

1

insert_tape( ( int)msg->data);

break.

case MSG_CLR_TAPE: 1

reclafo(myTid,"PLAY: Received CLR_TAPE\n");

clear tape();

break;

case MSG-ABS-TAPE:

recInfo (myTid, "PLAY: Received ABS_TAPE\a");

absorb tape();

break;

case MSG_TRANS_DDNE:

/* reclnlo (myTid, "ys: Received TRANS_DDNE\n", myName) */

fire- end ((iat ) msg->data)

break

case MSG_SET_TDK:

recInfo (=YT-4 d. "7.s: Received SET_TDK\a", mylame) */

set_token((dwo)m.sg-data);

break ;

casa MSG_ADD..TDKEN:

!* raeInfo ( myTid, "ys: Received ADD_TDKU\u", myName) */

add_toker. ( ( iat)msg->data)

break

case MSC 5UB_'avKEF:

recInfo (ayfic., "%s: Received SUB_TDM\n", myName) */

su token (( int)msg->dxta)

break ;

case MSG CHK_FIRE-TRANS:

recInfo (xyiid, "%s: Received CU,_FIRE_ITUUS\n", myName) ; */

it (go z= TRUE)

{if (trans _tok_enabled( ( int)msg->data))

{if (t: ans _pre_enabled((int)msg- >data))

{/* reclnlo (myTid,"%s: Firing transition Wa",myZla o,

(int)msg->data); *:

fire_start((ia.t)msg->data);

if (done_firing( ( int)msg->data))

fire_eadWzt)msg->data);
break

case MSG-SET-MODE:

mode = (int)msg->data;

break;

case MSG-ATELA:

go = FALSE;

break;

E .

}

/* execute subnet if no msgs are waiting */

if ((go == TRUE)At(mode == CONTINUOUS))

{

ehile (msgQueueCount(myTid) _= 0)

{

t_num = get-ready trans();

if (t_aum =_ -1)

{

usleep (500)

continue

}

/* recInfo(myTid, "\n%s: *** Firing Trans '%s' C/i] ***\a",

mylame, trans[t num].name, t-num) */

fire-start(t_num);

if (done_firing(t_num))

fire-end(t_nmm) ;

}

}

/* execute subnet if no msgs are waiting */

if ((go == TRUE)tt(mode =-- SINGLE-STEP))

{

/* recInfo(myTid,"ys checking hidden transitions\n",myName); */

while (msgQueueCount(myTid) = 0)

{

t_aum = get-ready-hidden-trans();

if

{

usleep (SOO)

continue

}

recInfo(globTid,"Firing hidden trans Y.s\n",

trans Et num].name)'; */

fire_start(t n•:=);

if (done_fizing(t_num))

fire-end(t_num);

}

}

/* exit event handler task via default processing */

return (msgDefault?roc (myTid, msg))

}
/*####*#### srsr###*######**#*r#rr#*#*##iil♦## r#rr#r##i#**###**#**#*!#!###*#i*#* 

get-updates - returns update list as char string of tid's

***###*rrrrrr#r#####rr#sssssrrs*s*#*#*#*****##r#**# ####** # *s**#*##*#*:*##*/

j char *get_updates (UPDATES *ps)

static char but [803

char *p

*but = '\0'

p = but ;

while (ps)

sprintf ( p, " 4,f.4x:%i", ps->tid, ps->num)

P = but + strlen ( buf)

ps = ps->next

return (but)

/*#*r*r*rrr*rr#**rrrr*#rr#r*rr**r#*rrr*#rr##rr*rr***#**#**##***#**#*******#*^t**

printPTinfo - print place a transition information

void printPTinfo U

int i

if (!strncasecmp (myName, "PNET_A", 6))

sleep (1) ;

else if (!stracasecmp (myName, "PNET_B", 6))

sleep (2) ;

recInfo (globTid., ^wNet Name: %s\n", myffame)

recInfo (glob:id, "PLACES [%il \n", num_pl)

for (i=0; i<aum_pl; i++)

{

/* recInfo (glo.)Tid, "\t%6s %4.1f %4. 1f 7.2i\n", place[i]-name,

Place Lil.z_loc_in, place[il.y_loc-in, place Cil.orig_token)

recInfo (globT..d, "\t'/.12s %8z 7.4x ys\n", place[il.name,

place [il.id , place [il.owaer,

get updates ( place [il.update))

}

recInfo (globTid, "TRANSITIONS ['/. il\n", uum_tr)

for (i=C; i<num_tr; i++)

{

i recInfo (elobTid, "\t%6s %4.1f %4.1f %2i %2i\n". trans[il.name,

` trans[il . x_loc_in, trans[il . y-loc_in,

cntAres(trans[il.inp_arc), cntkres(trans[il.out_arc))

I

recInfo ( globTic, " \ t%12s %Sx 7.4x %s\n". trans[il.name,

trans [il. id, trans[il.owuer,

get_updates(trams[il.update))

}
cntAres - count number of arcs in list

#ww#*wwsswssrww*•wssr#wwww*ww####**##**##*#w##*###*##*+WS:i##4+R##*+r###^#***#####/

int cntAres (struct Arc *p) 

{

int cnt = 0

while (p)

P = p->next 

cat++ ;

return ( cut)

/*s*ws**wraw*wswwwwwsssss*ssswss**ssw#ssss#wsssssw#sws**#*s#w*w#^**sw#w***w***#

register-remote - sends request msgs to register remote nodes 

##s*ws#w#wwwswwswwsswsws*wws##ssw*ss##***ww#www##w*w***##**#*#**s#*#s*#^****#*/ 

STATUS register-remote ()

int i

REG_REMOTE *ps

/* se^d msg for each remote place */

for (i=0; i<num_pl; i++)

{ 

it (place[il . owner != globTid)

ps = (REG_REMOTE *) malloc ( sizeof ( REG_REMOTE))

strcpy 

strcpy 

(

(

ps->sym

ps->act

_

_

name, place

name, place[il

[il.name

. act_name)

ps->type = PLACE-NODE ;

msgBuildSend (place [il.owner, globTid, MSG_REGISTER_RBMOTE,

(void *) ps, sizeof (REG_REMOTE),

MF_STANDARD)

/* send msg for each remote transition */

for (i=0; i<uum_tr; i++)

{

if (trans[il . owner != globTid)

{

ps = (REG_REMOTE *) malloc (sizeof (REG_REMOTE))

strcpy (ps->sym_name, trans [il.name) ;

strcpy ( ps->act_name, trans[i] . act_name)

ps->type = TRANS_10DE ;

msgBuildSend ( trans [i] . owner, globTid, MSG_REGISTER_gEMOTE,

(void *) ps, sizeof (REG_REMOTE),

MF_STANDARD)

}

return (OK)

/#ss*w#sssswsssss#ssssws*ss*ss***ssssss**ss*ss*s* s #***#***+w*#wws^##*w#***wssa#*

confirm—remote — send return msg with remote nods's id

*sss#ss##swssssswwsssssw#wss#wwsw#*s ♦ wawwsswwss#*ws4s*#**#**#,s *#*#w#*##^e####*#/

STATUS confirm remote (TID_TYPE regTid, REG_REMOTE *ps)
{

int lads

REG_REMOTE *pret

/* allocate return msg */

Prot - (REG_REMOTE *) malloc ( sizeof ( REG_REMOTE))

strcpy (prat->sym_name, ps->sym_name) ;

strcpy ( prat-->act_name, ps->act_aame) ;

pret->type = ps->type ;

/* find place or transition */

switch (ps->type)

{

case PLACE-NODE:

/* find local index */

if ((indx = find place ( ( char *)Ps->act _name)) < 0)

1. recInfo (globTid, "Could not find place '%3' by name\n",

ps->act_name)

free (pret)

return ( ERROR)

}

/* send return msg containing id */

pret->id = MAKE_ID (globTid, PLACE-NODE, indx)

msgBuildSend (regTid, globTid, NSG CONFIRM-REMOTE,

(void *) Prot, sizeof ( REG_REMOTE),

XFF_STANDARD)

break ;

case TRANS BODE:

/* find local index */

if ((indx = find trans ( ( char *) ps->act_name)) < 0)

{

recInfo (globTid, "Could not find trans I %s' by name\n",

- ps->act_name)

free ( prat) ;

return ( ERROR)

}

/* send return msg containing id */

prat->id = MAKE_ID (globTid, TRANS -NODE, indx)

msgBuildSend (regTid, globTid, MSG_CONFIRM_REMOTE,

(void *) Prot, sizeof ( REG_REMOTE),

f MF_STANDARD)

-j

I1 break

}

return (OK)

}

/»»»s»»*s»s»«»»»ss»«»s»s»s«**»»»«»ss*s»«»««»s«»»s»»»»»»s»»»»»*»s»»»»s*»*»»s*»»«

save remote - save data from confirm remote msg

»s»»s»ss»»»««s«s»»s«s«»«»»ss«.«»«»s«»«»s»»»»»»»»»»»»»»»*»»»»»»s»»»»»»»^*»»»»»»/

STATUS save remote ( REG_REMOTE *ps)

{

int indx

/* find place or transition */

switch (ps->type)

r
case PLACE-NODE:

/* find local index */ 

if ((infix = find-place ((char *)ps-1sym-name)) < 0)

recInfo (globTid, "Could not find place ' ys' by name\a",

return ( ERROR) 

/* save id of remote place */

place[indx].id = pa->id

break 

case TRANS-RODE:

/* find local index */

if ((iadx = find-trans ((char *)ps->sym-name)) < 0) 

{

recIafo(globTid,"Could not find trans ' y.s' by name\a",

ps->sym-aame);

return (ERROR)

}

/* save id of remote trans */

trans [indx] . id = p -i->id 

break

}

return (OK)

}

/########################################i##iii##############i#####*###########

save-update - save data from update register t reply with node id 

STATUS save -update (MSG TYPE *m)

int Jindx

int id

char *name

UPDATES *pupd

TID-TYPE myTid

REG-REMOTE *ps

/* parse message */

myTid = m->dest

ps = (REG-REMOTE *) m->data

/* find place or transition */

switch (ps->type) 

case PLACE BODE:

/* find local index */

if ((indx = find-place ( ( char *)ps->act-name)) < 0)±

recInfo (myTid, " Could not find place ' %s' by name\n",

ps->act-name)

return ( ERROR) 

/* save id for reply msg */

id = place [indx] . id 
/* add to update list */

pupd = (UPDATES *) malloc (sizeof (UPDATES))

pupd->next = place[indx].updrte

place [indx].update = pupd

pupd->tid = m->source

pupd->num = ps->id

break ;

case TRANS-NODE:

/* find local index */

if ((indx = find trans ((char *)ps->act_name)) < 0)

recInfo (myTid,"Could not find trans 'Y,s' by name\n".

ps->act_name)

return (ERROR) ;

/* save id for reply msg */

id = trans[indx].id ;

/* add to update list */

pupd = (UPDATES *) malloc (sizeof (UPDATES))

pupd->next = trans[indx].update

j trans[indx].update = pupd

s pupd->tid = m->source

pupd->num = ps ->id ;

pupd->which = ps->vhich;

recInfo(globTid,"Saved update for trans %s, update = Y,d\n".

trans[iudx].name, trans[indx].update); *!

break

}

/* send id in reply msg */

msgReply (m, (void *) id, MS_NONE. MF_STANDARD)

i return (OK)

}

Jir

initial marking - send initial marking to displays

- #########-+#*##s#####*#sss#sss####s#**##s##############:##*#######*############/

STATUS i...itial_marking ()

int i

UPDATES *pu

/* check each place */

for (i=C; i<uum_pl; i++)

akip places with no marking, or no updates */

if ((place[i].orig_token == 0) II

((pu = place [i].update) == NULL))

continue

/* loop through list *l 

While (pu)

{

msgBuildSend (pu->tid, globTid, MSG_SET-TOK,

(void *) ((pu->num A W000f*_ff)
I (place[il.orig-tuken << 101,

NS-HONK, XF-STAVDARD) ;

J* recInto (globTid,"Initial marker^=Y,2i in place 'Xs .%S' on display YAW

plaue[il.orig-token, myName, placecTuame, pu->tid) ; *!

pu = pu->next

}

}

retuza (OK)

}

C.3 Xplay.c — Test.3 and Fires Transitions

*include <X11/Xlib.h>

*include <X11iXuti?..h>

#include <X11/Xos.h>

#include <X11/Xatom.h>

#include <z tdio.b>

#include "ctos.h"

*include "btsLib.h"

*include "Global def.h"

#include "msb.h"

#include "Global-var_p"

*include °'^?lay.p"

exte:-n <hax *mlVaxe

/*****s*:r*********^**^*****::cs****«*s*****r*******ssss*ss*s*s*s******s***

* gat_ready-transO

* This routine selects the nest transition to fire. It is

* currently based on a ps..udo-random method, with some

* consideration giveu to speed. It returns -1 it no

* transitions are enabled.

int get-ready-trans(void)

{

int current, start;

start = random() % num-yr;

current = stars;

do

{

/* recInto(O."W Checking transition %i out of %i\n",

myName, current, num-tr)

it (trans-tok-enabled(current))

{if (trans_pre_enabled(current))

returr.(current);

};

current = (current+l) 7.num-tr;

}

while(current !- start);

return(-I);

}
8

/#*CMS******+r*+^***#***#*******s**s*a*4*********#*#*:^*s**#s#*####+ie****#k**#*

* get-ready-hidden-trans

* This routine selects the ag st hidden transition to fire. It is

* currently based on a pseudo-raadom method, with come

* consideration given to speed. it returns -1 if no

* transitions are enabled,

int get-ready-hidden-trans(void)

{

int current, start;

start = random() % num-tr;

current = start;

do

/* recInfo(G,"%s: Checking transition %i out of %i\n",

myName, current, num_tr)

if (hidden(current) == TRUE)

{if (trans_trrc_erabled(current))

+ {if (traas_pre_enabled(current))

i return(current);

current = (current+l)'1.num-tr;

}

vhile(current != start);

return(-1);

}

i * hidden()

i * This routine checks if the transitioa is not visible

* on any display.

~ int hidden(int t-num)

y- {

UPDATES *p;

P = trans [t-num].Update;

while (p ?= NULL)

{if ((p->vhich == T-START)II(p->which == T-BOTH))

{/* reclnfo(globTid,"Trans %s is visible\n", trans [t_nu4 .name); */

retusn(FALSE);

p = p->nezt;

/* reclnfo(gloaTid,"Trans %s is hiddon with update: %d\n",

trams [t-nwal.name, trans [t_auml.update); */

return(TRUE);

* done-firingO

* This routine checks if the fired transition should

* complete the firing cycle immediately. On7.y blocking

* transitions should not finish immediately.

i
int doae_firing( int t_num)

{

if (trans[t_auml.post_type == F_REMOTE)

return( FALSE);

else

return ( TRUE);' 

* set token() 

* This routine sets the number of tokens in the given place. 

void set token( int data)

{

int p_num, num_tok; 

num_tok = (datakOxffff000O)»16;

p_num = datakOxffff;

place[p_nu=].curr_token = num_tok;

disp_set_tok(p_num);

}

* sub-token(

* This routine subtracts a number of tokens to the given place.

void sub_token ( int data)

int p_num, num_tok;

num_tok = (datakOxffffOOOO)»16;

p_num = datakOxffff;

place[p_numl.curr_token -= num_tok;

if (place[p numl.curr_token < 0)

,place[p_numl.curr_token = 0;

disp_set_tok (p_num);

}

/##*##**#**^^*aszssas-:a#*^*#me^r^yeia::^ia*#######*###^###*########**###*^ 

* add_tokeno

* This routii, e adds a number of tokens to the given place.

void add_token ( int data)

{

int p_num, num_tok;

num_tok = (datakOxffffOOOO)»16;

p_num = datakOxfflf;

place[p_numl.cur._token += num_tok; 

it (place[p_numl.curr_token < 0)

place [p_numl.curr_token = 0;

disp_set_tok (p_nu=);
/########+R##*###t####M#*###########^h^M##########^h#########i################

* trans_pre_enabledo

* This routine checks it both the tape requirements and

* the enabling function requirements for firing a

transition are met, as well as if the transition is

* currently not firing. 

int trans_pre_enabled(iat i)

fat enabled : TRUE;

if (trans[il-firing)

return(FALSE); 

if (trans [il . toppe_req)

{if (trs[i7.tape_req != query_tape()) an 

returu( FUSE);

if (trans[il.enable iunc != NULL)

{if (trans[il .enable_type == F_LCCAL) 

enabled = ( *trans [i .enable_fune)(trans[il,enable_action. 

traas [il.enable_vai

I /* reclnfo(globTid,"Transitiou Vd enabling: Wn",i,enabled); */ 

return ( enabled);

* trans tok_enabledo

* This routine checks if the token requirements for firing

* a transition, are met. Both multiplicity and inhibitor arcs

1 * are checked.*

iat trans tok_enabled ( int i)

{

struct Arc *are-a;

^•• arc_a = trans [il • inp_arc; 

while ( arc_a)

{if (place [arc_a->placel . curr_token < are_a->mult)

f return( FALSE);

arc_a = arc_a->aext;

arc-a = trans[il.inh_arc;

while ( arc_a)

{if (place [arc_a->placel.curr_token)

return(FALSE);

arc_a = are_a->next;

return(TRUE);

}
* tire-start(

* This routine starts the tiring of a transition. It removes

* tho appropriate tokens, absorbs any tape command and calls

* the post function.

void tire_ start ( int i)

{struct Arc *arc_a;

trans [il.firing = TRUE;

arc_a = trans[il . inp_arc;

ohile(arc_a)

{place [arc_a->placel.curr_token -= arc_a->mult; 

disp_ set_tok ( arc-a->place);

arc_a = arc_a->next; 

it (trans[il.tape_req)

{absorb tape(); }; 

if (trans[il.post_func)

it (trans[il•post type == F_LOCAL)

(*trans[il.post _2unc) ( trans [il . post_action, trans[il.post-var); 

also 

{O+trans[il . post_func)(i, transCil . post_tid,

trans[il.post_action, trans[il.y .:._ rta);

recInfo (globTid,"Ys: Executed remote post function\n",ryName);

}i 

disp_start _f ire(i);

}

/****s********. s** *s**********ri*s***s*sss***s*** *s**s*****************

* fire end()

* This routine ends the tiring of a transition. It updates

* the number of tokens in each output place.

s/

void f ire_end(int i)

{

struct Are *arc_a;

trans [il .firing = FALSE;

arc_a = trans[i] out-arc;

ahile ( arc_a)

(place [arc_a->placel . c=r_token += arc_a->mult;

disp_set_tok ( arc_a->place); 

arc_a arc_a->next;

disp_end_tire(i); 

CA enable_func.c -- Local and Remote Enabling Functions

#include <stdio.h>
*include " ctos.h"

*include "domLib.h"

*include " Global-def.h"

*include "Global var.p"

/RMtRRt##AtA###tA#####t#iRA##t######t#tttRtttMARRRRttRRtRRttttRtRRRRtR#AtR

* Assorted enabling-!unctions()

* Below is a bunch of small enabling functions. Done and

* not-done and used for looping

s/

int gt(int action, int data)

{

int var;

char buff [201

recPrompt(globTid, buff, "Enter greater than rd to fire: ", data);

sscant (buff,"U",tvar);

it (data < var)

return(TRUE);

also

returu (FALSE);

}

int lt ( int action, iat data)

{

int var;

char butt [20] ;

reePrompt ( globTid, butt, " Enter less than %d to fire: ", data);

sscant ( buff , "Xd",Avar);

it (data > var)

return(TRUE);

else

return(FALSE);

int done ( int action, int data)

{

if (action == 1) /* Return TRUE if variable = 0 */

{if (read-var ( data))

return(FALSE);

else

return (TRUE);

}

also it (action == -1) /* Return TRUE it variable != 0 */

{it (read-var (data))

return(TRUE);

also

return(FALSE);

}

int not-done ( int action, int data)

{

it (!read-var ( data))

return(FALSE);

else

return(TRUE);

}
int DOM_bool(int action, int data)

{

int *DOH value;

char *str_ptr;

str_ptr = get_var_name(data);

recInfo(globTid, "Executing DOM_bool for U. I hope you wanted to!\n".str_ptr

if ((DOM_value = (int *)objCopy(globTid.str _ptr)) — BULL)

{reclnfo(globTid,"ERROR: Object ys not found in Data Object Manager\n".

str_ptr);

return(FALSE);

if (action == 1)

{if (*DOH_value)

return(TRUE);

also

return(FALSE);

}

else it (action == -1)

{if (*DOH_value)

return(FALSE);

else

return(TRUE);

}

}

int DOM_done(int action, int data)

{

int *DOM_value;

if ((DOM value = (int *)objCopy(globTid.data)) _= BULL)

(recInfo(globTid."ERROR: Object ys not Sound in Data Object ManagerV0 .

data) ;

return(FALSE);

if (action == 1)

{if (*DOM_value)

retu-n(FALSE);

also

return(TRUE);

}

else if (action == -1)

{if (*DOM_value)

return(TRUE);

also

return(FALSE);

}

}

* enable table q

* This array equates the symboli , ; names of the eatbling

+ functions with the actual function pointer.

#define MAI_EBAE.2 6

struct tune-entry enable_table q
({DOM_bool, "DOM_bool"}.

{DOM_done, "DOM_done"},

{gt,"greator_than"}.

(lt, "less than").

{done, "done"},

(not-done. "act done"}

};

• find enable()

* This routine raturns a pointer to the enabling function

» specified by its symbolic .name.

void *f ind _ enable(name)

E char *name;

{int i;

it 0strcmp ( nsme,"0"))

!

return ( NULL);

t

for(irO;i<MAX_ENABLE;i++)

{ i {if (!s^ramp(name,enable_tableLi].i.dent_str))

raturn( ( void *) enable_table [i].fuac_ptr);

raturn((void *)-i);

}

C.5 postrfunc.c -- Local and Remote Post Functions

#include < stdio.h>

*include "Global def.h"

#include " Global_var.p"

*include "domLib.h"

#include " coordTools.h"

ltinclude "msg.h"

/w»»*»ww«www»»»w»«»»»*:wwwwwwwww+^*wwwwww*www*w**ws**wwww**w*www*^:wwswwwsw»

* Assorted post functions()

* Below is a bunch of small post functions. Initialize and

* decrement are "sod for looping, but only have on-a

t variable to work with! Do not use two loops with these....

int alive ( int action, int data)

{reclafo (globTid, " Alive: %d\n", action);

}

int live_init(int action, int data)

{

char buff [101 ;

int Val;

/* reclnfo(globTid,"Inside initi alize\n"); */

recPrompt ( globTid, buff, "Enter variable value: ");

zscant(butf,"%d".tval);
save var(data, val);

}

int initialize( int action, int data)

{

save_var( data, action);

}

int decrement ( int action, int data)

{

int Val;

val = read_var(data);

savevar(data. ( val-action));

}

int increment ( int action, int data)

{

int val;

val = read var (data);

save_var(data, (val+action));

}

int renameOBJ ( int action, int data)

{

char *str_ptr;

str-ptr = (char *)get var_name(data);

recIafo (globTid, "Obj before rename= ' Xs'\n", str_ptr)

if (renameObjs (globTid, str_ptr) == ERROR)

recInto (globTid, "renam3Objs Error: could not rename '%s'\n",str_ptr);

else

recInfo (globTid, "renameObjs successfully renamed °%s'\n",str_ptr);

str_ptr = ( char *) get var_name ( data);

reclnfo (globTid,"Obj after rename = ' 7.s'\n str_ptr)

int duplicateOBJ ( int action, int data)

{

char *str_ptr;

str_ptr = ( char *) getvar_name(data);

recInfo ( globTid, "Obj before dup= 'Xs' \a", str_ptr)

if (duplicate0bjs ( globTid, str_ptr) == ERROR)

recInfo(globTid, "dupObjs Error: could not dup I%s' \n".str_ptr);

else

recInto (globTid, "dupObjs successfully dup'd ' %s'\n",str_ptr);

str_p = = (char *) get_var_name ( data);

recInfo (globTid,"Obj after dup= I %s'\n", str_ptr)

}

* send_post_msg()

* This routine builds and sends a message to the appropriate

* post function server.

int send_post_msg(int infix. TID_TYPE dest_tid, int action, char *data)

{

POST-DATA p_data;
p data.indx = indx;

p data.action = action;

strcpy(p_data.data_obj. data); 

msgBuildSend ( dest_tid, globTid, HSG TRANS JIRED, (void *) kp_data,

sizeof (p_data), MF_STANDARD);

} 

/*******ssssss:ssssss*s******s*s*ssss***ssss******************* s***, s.^ ****

* post-table[I 

* This array equates the symbolic names of the post *unction

* with the actual function pointer.

#define MAX-POST 8

struct func_entry post_table O =

{{send-post msg,REMOTf. _POST_FUNC},

{renameOBJ ,1' rename0bjs"},

i {duplicateOBJ."dupObjs"},

{alive,"alive"},

{initialize, " initialize"I,

{live_init,"live_init"},

{decrement, " decrement"},

{increment, " increment"}

/*ss*****sass:****************************** *s**************************** 

+ find_posto 

* This routine returns a pointer to the post function

* specified by its symbolic name.

void *f ind_post(name) 

char *name;

int i;

if 0strcmp(name,"0"))

i return ( NULL);

for(i=O ; i<MAX_POST;i++)

{if (! strcmp (name.po3t_table[il.ident_str))

i return((void *)post_table[il.fuac_ptr);

return((void *)-1);

}

/* "rename" POST-LOCAL function */

STATUS renameObjs ( TID TYPE t, char *obj_string)

{

# define MAX_OBJS 16

int i, num_objs

char *name[MAX_OBJS] _ {NULL}

char *obis ;
N.

90

objs = (char *) malloc (strlen(obj_3tring)+1)

strcpy (objs, obj_string) ;

if ((num objs = parseNames (objs, name)) _= ERROR)

{

recInfo(t,"renameObjs ERROR: could not parse '7,s'\n", obj_string)

free (objs) ;

return (ERROR)

}

for (i=0; i<num_objs; i+=2)

{

if ( (name [i] ==NULL)II (name [i+1]==NULL))

{

recinio(t,"renameObjs ERROR: one of the names was null\n")

free (objs)

return (OK)

}

if (objRename(t, name[i], name[i+13) ==ERROR)

{

free (objs)

recInfo(t,"renameObjs ERROR: objRename returned error\n")

return (ERROR)

}

recInfo(t,"Successfully renamed '%s' as 1 %s'\n 1 , name[i], name[i+?.])

}

free (objs)

return (OK)

}

/* "duplicate" POST_LOCAL function */

STATUS duplicateObjs (TID_TYPE t, char *obj_string)

{

# define MAZ_OBJS 16

int i, num_objs

char *name[MLI-OBJS] = {NULL}

char *objs ;

objs = (char *) malloc (strlen(obj_string)+1)

strcpy (objs, obj_string) ;

if ((num_objs = parselames (objs, name)) == ERROR)

{

reclnfo(t,"duplicateObjs ERROR: could not parse ''/s'\a", obj_striag)

free (objs)

retux-a (ERROR)

}

for (i=0; i<aum_objs; i+=2)

{

if ((name[i]==NL:.L)II (name [i+1]==NULL))

{

recInfo(t,"duplica6zObjs ERROR: one of the names was null\n")

free (objs)

return (OK)

}
I r

9

if (objDup(t, name[i], name[i+11) _- ERROR)

{

recInfo(t;"duplicateObjs ERROR: objDup returned error\n")

free (objs) ;

return (ERROR)

}

recInf o(t, "Successfully duplicated '%s' as '%s'\n",

name Ci] , name [i+1] )

}

free (obis)

return (OK) 

C.6 tapes — Tape Commands

#include <stdio.h>

#include "Global_def.h"

#include "Global_var.p"

* init-tape()

* This routine initializes the tape list. You should use

* clear-tape() instead, as it free's the memory used by

* the tape elements as well.

void init-tape(void)

{

head = NULL;

tail = NULL;

}

* append tapeO

* This routine appends a tape command onto the end of the

* tape list. This is the standard method of adding a tape

* command.

void appendtape(int command)

{

struct tape-node *tmp;

tmp = (struct tape node *)malloc(sizeof(struct tape-node));

if (head)

{tail->next = tmp;

tail = tmp;

tail->id = command;

tail->next = NULL;

}

else

{head = tmp;

tail = head;

tail->id = command;

tail->next = NULL;
I.

}

/*rr**rr**rs********************ssssssr**r :** *sssrrrs*******r*rr******

* insert tape()

* This routine inserts a tape command onto the head of the

* tape list. This is not a standard use of the tape, but

* provides for greater flexibility and exception handling.

void insert _tape (int command)

{

struct tape node *tmp;

tap = (struct tape -node *)malloc(sizeof(struct tape-node));

if (head)

{tmp->next = head;

head = tmp;

head->id = command;

}

else

{head = tmp;

tail = head;

head->id = command;

}

/******r*rr*******************..***rsr*rr**ss*r*r***r*****err***r**********

* query_tapeO

* This routine returns the command at the head of the tape,

* without removing it. This is used to check if a transition's

* tape requir=ent is satisfied for enabling.

int query-tape(void)

{

if (head)

return(head->id);

else

return(-1);

}

/**s******r*r*************s*********srss**sr rs** ****r*****************

* absorb tape()

* This routine returns the command at the head of the tape,

* then removes it from the list.

int absorb-tape(void)

{

struct tape-node *tmp;

int id;

if (head)

{id = head->id;

tmp = head;

if (head == tail)

tail = NULL;

head = head->next;

free(tmp);
}

also

id = -1;

return(id);

i * clear-tape()

* This routine removes all of the tape commands from the

* the tape list, and sets the head and tail pointers to NULL.

void clear-tape(void)

{

{ struct tape-node *tmpl, *tmp2;

tmpl = head;

while(tmpl)

{tmp2 = tmpl->next;

free (tmpl);

tmpl = tmp2;

! head = NULL;

tail = NULL;

* find-tape()

* This routine returns the tape command id for the given

* symbolic name. If the name is not valid, -1 is returned.

int find_tape(char *name)

{int i;

if 0strcmp(name,"0"))

return(MULL);

for(i=O;i<MAX-TAPE;i++)

{if (!strcmp(name,tape table[il.ident-str))

return(tape _table[il.id);

}return(-i);

ii * f ind-tape-name()

1

e This routine returns the symbolic name of the given

1111 * tape command id. If the id is not valid, NULL is retuned.

char *find-tape-name(int id)

int i;

j for(i=0;i<MAX_TAPE;i++)

i 0
{if (id == tape _table [ il.id)

return(tape_tableCil.ident_str);

return(NULL);

}

* get_tape_command()

* This routine queries the user for a tape command, and

* returns his selection. This is used for testing purposes.

int get_tape-command(void)

{

int select, i;

fprintf ( stderr,"\nTape CommandsAn");

for(i=O ; i<MAX_TAPE;i++)

fprintf(stderr," %d: %s\n",i,tape_table[il.ident-str);

fprintf ( stderr," %d: No selection\n",i);

fprintf ( stderr," \nSelection: ");

fscanf(stdin,"U",&select);

if (select == MAX-TAPE)

{fprintf ( stderr, "No selection\n");

return(0);

};

if ((select<0)II(select>MAX_TAPE))

{fprintf ( stderr,"%d is not a valid command\n");

return(0);

fprintf(stderr,"%s\n",tape_table[selectl.ident_str);

return( tape-table[select].id);

}

f

C.7 load_net.c — Loads the Petri Net Configuration File

t File: load_net.c

Purpose: reads player and display configuration files

Author: Joe Peck

revised: Don Lefebvre

Revised: 20 Aug'91

^► »***»ww##w##»#»www»rs»w#»#*###»»»»»#www»»**##w##»»»»»»#»##w»»»»»*w*www»»*ww»**

/*------------------------------------- include files -------------------*

*include <X11/Xlib.h>

#include <Xii/Xutil.h>

#include <X11/Xos.h>

#include <X1i/Xatom.h>

#include <stdio.h>

#include <math.h>
#include " Global_def.h"

#include " Global_var.p"

#include " 7ecLib.h"

#include : ctos.h>

extern char *myName

/*--------- function prototypes 

void *f ind_enable

void *f ind_post ()

int find-place (char *name) ;

int find-trans (char *name) ;

void do-error (char *s) ;

STATUS read_subnet_config (FILE *infile)

STATUS read_display_config (FILE *infile)

TID_TYPE find_oQner (char *owner)

- /#######*#iii#ti#iii#i#i##i*ii#i#ii#ii###i################i#################

load-net - load configuration file

----------------------------------------------------------------------------

RETURNS: OK or ERROR indicating success in reading config file

INPUTS: char *net_conf ig_f ile - name of configuration file

int type - type of config file ( CF_PNET or CF_DISP

*i##i#############*i######i##it# ##i#ii#iiiii#iiii**##*i****#*##*#qe*********i

STATUS load-net (char *net_config_file, int type)

{

FILE *fp; /* Temporary file pointer */

char file_name [MAXLINE]; /* Actual file to open */

f int i, j, k, 1; /* Generic loop variables */

char linebuf[MAXLINE]; /* Generic buffer for line reads */

1 char name [MAXLINE]; /* Used to read object names */

FILE * infile; /* File pointer to input file */

char comment [ 10][MAXLINE]; /* Allow for ten lines of comments */

^ struct Arc *azc_a, *arcb ; /* Pointers to arc structures */

struct Arc point *arc point-a, *arc point-b;

int num_points; /* Number of points in an arc */

in*, num_ares; /* Number of arcs per type */

int dummy; /* Generic variable */

int num_read; /* Number of items read by fscanf */

^ /* Create config file name */

switch (type)

{

! case CF_DISP:

sprintf ( file-name, "%s.%s", net-config-file, "disp")

break ;

e

case CF_PNET:

sprintf (file name, net "fiS.li3", _config-file, "pnet")

break

default:

strcpy (file name, net-config-tile)

}

/* Open the config file */
i .'

if (fp = fopen ( fila_name,"r"))

{

infile = 1p;

}

else

{

sprintf ( linebuf, "Could not open config file %s", filename)

do-error ( linebuf)

return ( ERROR)

}

/* Interpret Comment */

while( ( int)f gets ( linabuf . MAXLINE , inf ile)! =EOF)

{if ((linebuf [O] __ 1 1')kk ( linebuf[1] =_ 'O')kk(linebuf [2] __ 111))

break;

};

i=0;

while((int)tgets(comment[i],MAXLINE,infiid)!=EOF)

{if ( ( comment [i] [0] == ' I ') Ak (comment [i] [1] == ' fin') )

{comment [i] [0] = NULL;

break;

it (++i > 9)

i=9;

};

/* Get the number of objects is the net */

f scant (iafile,'I t %d %d '/.d %d '/.d %din', knum mp, $mum_pl, Rnum_rp,

knum_tr, kuum_gr. kaum_cs);

/* Allocate work arrays */

place = ( struct Place *) malloc ( num_pl* sizeof ( struct Place));

trans = ( struct Trans *) malloc (num_tr* sizeof ( struct Trans));

if (num_mp > 0)

mpar - ( struct MPar *)malloc (aum_mp*sizeof(struct MPar));

it (aum_rp >0)

rpar = ( struct RPar *) malloc ( num_rp *sizeof ( struct RPar));

/* Process marking parameters *%

for (i=0;i<num_mp;i++)

{num_read = f scant ( infile,"%s %d %f U U11 , name. kmpar [i].num_token,

kmpar[i] . tag_x_ia, kmpar[i] . tag_y_in, ampar [i].layer);

it (num_read != 5)

do_error( " Missing information for marking parameter");

dummy = mpar[i] . layer; /* Each layer is indicated by a bit mask */

mpar[i] . layer = 1;

while ( dummy)

{mpar [ i].layer 1 = 1«d1immy;

f s cant (inf ile, "U", Mummy)

};

mpar[i] . name = ( char *) malloc ( strlen( name)+1);

strcpy(mpa.r[i] . name , name);
9

J

/* Process place information */

for (i=O;i<num_pl;i++) 

(num_read = tscant(infile, 11%s %d %f %f %f %f %d", name,

&place[il.orig_token, &place[il.x_loc_in, &place[il.y_loc_in,

&place[il.tag_x_in, &placeCil.tag_y_in, &place[i].layer);

if (num_read != 7)

do_error("Hissing information for place definition");

dummy = place[il.layer;

place[il.layer = 1;

while (dummy)

(place[il.layer 1 = 1«dummy;

i s cant (inf ile , " U" , &dummy) ;

};

j place[il.name = (char *)ma1loc(strlen(name)+1);

I strcpy (place [il. name, name);

place[il.curr_token = place[il.orig-token;

it (place[il.orig_token < 0) /* decode place marking */

(p/ace[il.curr_token = mpar[-place[il.orig_token - il.num_token;

place[il.ori3_token = place[il.curr_token;

t•

i

/* Process rate parameters

for (i=O;i<num_rp;i++) 

(num_read = tscanf(infile,"%s %f %f %f %d", name, &rpar[il.fire rate,

H &rpar[il.tag_x_in, &rpar[il.tag_y_in, &rpar[il.layer);

if (num_read != g)

do„error("Hissing information for rate parameter");

dummy = rpar[il.layer;

rpar[il.layer = 1;

while (dummy)

(rpar[il.layer 1 = 1«dummy;

fscant(i.-dile," Xd",&dummy);

rpar[il.name = (char *)mal1oc(strlen(name)+1);

strcpy(rpar[il.rame,name);

};

/* Ignore groups currently */

if (num_gr) /* get rid of last \n after previous line */

f s cant (inf ilR , " \n") ;

for (i=0;i<uum_gr;i++)

fgets(linebuf,HAXLIHE,intile);

/* Process Transition Information */

for (i=0;i<num_tr;i++)

(num_read =t scant (intile,"% 3 %t %d YA %d %d %f %f %I %f Yf %f %d", name,
&trans[i].fire_rate, tdummy, ttrans[i] . kind,

anum_arcs, ttrans[i]•orient, ttrans [ i].x_loc_in,

ttrans[i].y_loc _ in, ttrans [i].tag_x_in, ttrans[i].tag_y_in,

htrans[i]. rate- x_in, &trans[i]. rat e_y_in, ttrans [i].layer);

if (num-read != 13)

do_error("Missing information for transition definition");

dummy _ trans [ i].laper; 

trans[i].layer = 1; 

while (dummy)

(trans [ i].layer I = 1«dummy; 

f s cant (inf ile, "U" , &dummy) ;

trans[i] . name = ( char *) malloc ( strlen(name)+1);

strcpy ( trans[i] . name , name);

/* process input arc information */

for (j=O;j<num_ares;j++)

(arc_a = (struct Arc *) malloc ( sizeof(struct Arc));

num_read = fscanf ( iufile,"%d %d %d %d", &arc_a->mult , &arc-a->place,

tnum_points , karc_a->layer);

if (num_read != 4)

do_error( " Missing information for input arc definition");

dummy = arc_a- >layer;

arc_a->layer = 1;

while ( dummy)

(arc_a->layer 1= 1«dummy;

f scant (inf ile, "%d" Adummp) ;

arc_a->type = INPARC;

arc_a->place -= 1; /* GreatSPN arrays start at i ... yuck *%

if (j==0)

(trans [ i].inp- arc = arc a;

arc _b = arc_a;

el^^

(arc_b->next - arc-a;

arc_b = arc-a;

for (k=O;k<num_points ;k++)

(arc_point_a = (struct Arc point *)malloc ( sizeof

(struct Arc-point));

num-read = fscanf ( infile,"%f U W1 , karc-point _&->x_in, 

Aarc_point_a->y_in);

if (num-read != 2)

do_errox( " Missing input arc location information");

if (k==0)

(arc_b- > arc_points = arc_point_a;

arc_point_b = arc-point-a;

}

else

(arc_point _b->next = arc_poiat_a;

arc_point_b = arc-point-a;
arc_a->next = KULL;

};

/* process output arc information •/

num_read = fscanf(infile,"%d\n".k1);

if (num_read != 1)

do_error("Missing number of uutput arcs");

for (j=0;j<l;j++)

(arc_a = (struct Arc *)malloc(sizeof(struct Arc));

num_read = fscanf(inf ile,"%d %d %d %d", *arc _a->mult,&arc_a->place,

&uum_points,&arc_a->layer);

if (num_read != 4)

do_error("Missing information for output arc definition");

dummy = arc_a->layer;

arc_a->layer = 1;

while (dummy)

(arc_a->layer 1= 1«dummy;

fscanf(inf ile, "%d",&dummy);

};

arc_a-->type = OUTAAC;

arc_a->placo -= 1;

if ( j ==0 )

(trans[il.out_arc = arc-a;

arc_b = arc-a;

}

else

(arc b->uext = arc-a;

arc_b = arc_a;

};

for (k=O;k<nu.m_points ;k++)

(arc_point_a = (struct Arc-point *)malloc(sizeot

(struct Arc-point));

nun-read = fscanf(intile,"'lf %f\n", &arc_point_a->x_in,

&arc_point_a->y_in);

it (num_read != 2)

d^ -error ("Missing output arc location information");

if (k==0)

(arc_b->arc_points = arc_point_a;

arc-point-b = arc-point-a;

}

else

(arc_point_b->nert = arc-point-a;

arc_poiut_b = arc-point-a.

};

/* process inhibitor arc information */
`I

1

F

10

num_read = fscanf(infile," 7d\n".Z1);

if (num_read != 1)

do_error( " Missing number of inhibitor arcs");

for (j=O;j<l;

{arc_a = (struct Arc 

j' +). $ ) malloc ( sizeof ( s •:ruct Arc));

num_reed = fscanf ( infile . 11d VA %d %d". tarc_a->mult , karc_a->place, 

tnum_points . tarc_a->layer); 

it (num_read != 4)

do_error( " Missing information for inhibitor arc definition");

dummy = arc-a->layer; 

arc_a->layer = 1;

while ( dummy)

(arc_a->layer 1= 1«dummy;

f scanf (inf ile. "%d" . &dummy) ; 

arc_a->type = ISHARC;

arc_a->place -= 1;

if Q==n)

{trans ; il.inh_ arc = arc-a;

arc_b = arc-&;

else

(arc -b-next = arc-a;

arc_b = arc_a; 

for (k=0;k<num_poiuts ;k++)

{arc_point_a = (struct Arc-point •)malloc ( sizoof

(struct Arc-point));

num_read = fscant(infile."%f %f \n". &ar:_point_a->x_in, 

3arc_point_a->y_iu);

if (num-recd != 2)

do_error( " Kissing inhibitor arc location information");

if (k==0)

(arc_b->arc_points = arc_point_a;

arc-point b = arc-point-a;

}

else

{arc_po ' nt b->next = arc_poiat_a;

arc_poin,_b = arc-point-a;

/• now read subnet interconnection into •/

switch (type)

{

case CF DISP:

if (read_display _config ( infile) == ERROR)

close ( infile)

return ( ERROR)

}
break ;

case CF_PNET:

it (read_subnet_contig (infile) == ERROR)

{

close ( intile)

return ( ERROR)

}

break

}

/* arapup and exit */

close ( intile)

return (OK)

}

/wssssswswsssws»s*»sswwsssss»*s»swwss*ss*s»*»s*sw*s»*ss»s*wwsss*s*wwww*w**s**

find -place - find place number corresponding to name

*ss*s*sss*s»s»»*»»»ss»*s»»*»»ssssss»s»s»»sws*s*ss*s*sswww*****swwsw*s*******s

int tind_place ( char *name)

{

int i;

for(i=O;i<num_pl;i++)

it 0 strcmp(name,placeCil.name))

return(i);

return(-1);

I.

/*wwssssssswswss»»*s»**ss**ss»ssss»sswws**sssss»»ss*ss*s*w»ssswssw*ws**ww*w*s

find-trans - find transition number corresponding to name

w*s*wwwwssssss»*ssswws*»s»**»swwws**ss*****s*w***sss*ssww**s**s*w*****w*w*sww

int Lind-trans (char *name)

{

int i;

tcr(i=O;i<num_tr;i++)

it 0 strcmp(name,transCil.name))

return(i);

return(-1);

( /wsss ssswwwsssssw»ssww** sssss»ssss*s*ss*sss»sss ws*ssws»s*s*sss*ss** *wss*swsw*

do-error - print error string

- w*ssw*ssssrwwss»»»»»ss**w*s*ss**ssssswww***wssswwwwwwss*w**w**xwwwss *swswwwww

void do-error ( char *s)

{

recInfo (globTid, "ERROR: %s\n",$);

w

/*swwwwsss*s»s*sssswsss»ss*»»sssssww»s*s*s»s»»*ssssssssssww*ss**waw*ws*sssssss

read- subnet_coafig - read configuration of subnet player

wwwwss*sw»sssssws*s*sswsssswws*ss*ssw»ss»wwswwwwsswwsswswwwwww***ww**w*w*wwwww

STATUS read_subnet_confi$ (FILE *infile)

{char linebuf 02557

char ick C151C2557;

char sym_name 0401 ;

char buff C401 ;
a.

char func_name [40]

char loc [40]

char owner [40]

char name [40]

char action [40]

char data [255]

int indx ;

int i, imax;

void *ptr;

/* read remaining lines of file */

while (fgats (linebuf, KA;CLINE, infile) != NULL)

{

imax = sscanf(linebuf, "%s %s 7.s %s ys Ys ys %s %s ys Ys %s %s ys %s",

ick[0] , ick Ell, ick[2] , ick[3] , ick [4] , ick [5] , ick [6] , ick [T] ,

ick[8] , ick [9] , ick [10] , ick [i 1] , ick [12] , ick [13] , ick [141) ;

i=1;

/* process PLACE line */

if (! strncasecmp ( ick[0], "PLACE", 5))

{

strcpy(sym_name,ick[i++]);

strcpy(loc,ick[i++]);

if (! strucasecmp ( loc, "REMOTE", 5))

{

if (Undx = find-place (sym_uame)) < 0)

{

recI-ato (globTid, "Could not find place 'Y,s' by name\n",

sym_name)

continue

}

place [indx].act -name = (char *)malloc(strlea(ick[i])+1);

strcpy(place[indx].act_name,ick[i++]);

strcpy(owner,ick[i++]);

place[indx].owner = f ind_owner ( owner)

}

else

{

if ((infix = find-place ( sym_name)) < 0)

{

reclnfo ( globTid, "Could not find place ' %s' by name\a",

sym_name)

continue

}

place [indx] . owner = globTid

place [iudx] . id = MAKE_ID (globTid, PLACE MODE, indx)

place ndx].act -name = ( char *)ma3loc(strlea(sym_name)+1);

strcpy(place[indx].act_name, sym_name);

/* process TRANS line

also if (! strucasecmp (ick[O], "TRANS", 5))

{strcpy(sym_name,ick[i++]);

if ((indx = find-trans ( sym_name)) < 0)

{recInfo (globTid, "Could not find trans '%s' by name\a
1

sym_name)

continue

}

trans [ indxl . owner = globTid

trans [indx] . id = MAKE_ID ( globTid, TRANS -NODE. indx)

trans[indx].enable_type = F_NONE;

trans[indx] . post_type = F_NONE;

trans [indx] . update = NULL;

while ( i<imax)

{strcpy(buff,ick[i++]);

if (!strncasecmp ( buff, " ENABLE-LOCAL", 12))

{

trans[indx] . enable_type = F_LOCAL;

strcpy(fuuc_name , ick[i++]);

ptr = find_ enable ( func_name);

if ((int ) ptr == -1)

{recInfo ( globTid, "Could not find enabling

"function %s\n", func_name);

continue;

recInfo (globTid, "Found enabling function % s\n",func-name);

trans [indx . enable_func = ptr;

strcpy(action,ick[i++]);

trans [indx]. enable -act ion = atoi(action);

strcpy(data,ick[i++]);

if ((trans[indx]. enable - var = f ind_variable (data)) < 0)

recInfo (globTid, " Insufficient storage for ' ys'\n",

data);

}

also if (! strucasecmp ( buff, "POST-LOCAL", 10))

{

trans[indx] . post_type = F_LOCAL;

strcpy(func name,ick[i++]);

ptr = find_post ( func_name);

if ((int ) ptr

{recInfo ( globTid, "Could not find post function %s\n",

func_name);

continue;

trans[indx] . post_func = ptr;

•^ strcpy ( action , ick[i++]);

3 trans[iadx].post_action = atoi(action);

strcpy ( data , ick[i++]);

if ((trans[indx].post var = find-variable ( data)) < 0)

recInfo (globTid, " Insufficient storage for 'U'V",

data);

}

else if (! strucasecmp (buff, "POST-REMOTE", 11))

{

trans[indx] . post type = F_REMOTE;

trans[indx] . post_func = find_post (REMOTE_POST_-7 C);

if ((int ) ptr == -1)

{recInfo ( globTid, "Could not find post function %s\n",

REMOTE_POST_FUNC);

continue;
104

strcpy ( func_name , ick[i++]);

trans [indx].post_tid = find_ovner(func_name);

strcpy(action,ickCi++]);

trans[indx].post_actioa = atoi(action);

strcpy(data,ick[i++]);

trans[indx].post_data = (char *) malloc ( strlen(data) +1);

strcpy(trans[indx].post_data, data);

}

}

/* process SUBNET line */

else it (! strncasecmp ( ick[07, "SUBNET", 5))

{

strcpy ( name,ick[i++]);

net-name = (char +) malloc (strlen(name)+1)

strcpy (net -name, name)

}

/* ignor.e all other lines */

else recInfo(globTid,"Unrecognized parameter in conlig file: Wa ll ,

buff);

}

return (OK)

}

/*sssssssssssssss***e**s:ssss**s^*****ss*:ss*s*sssss*ss******s***s*sss****ssss*

read_display_config - read configuration of subnet display,

sssssssssssssss**s**sssssssssssssss*ssssssss+s***s*ss****s*s****ss***s*sss*s***/

STATUS read_display_config (FILE *infile)

char linebuf DMILINE]

char ick [15][40];

char buff [40]

char sym_name [40]

char act-name [40] ;

char disp [40]

char owner [40]

int indx ;

int i, imax;

TID_TYPE Lid ;

/* read remaining lines of file */

while (fgets (linebuf, KAILINE, infile) != NULL)

{

imax = sscaaf(linebuf, 11 %s %s %s %s %s %s %s %s /s %s %s %s %s %s y,5" ,

ick[0] , ick [1] , ick[2] , ick [3] , ick C4] , ick [5] , ick [6] , ick [7] ,

ick[8] , ick[9] , ick[10] , ick[ll] , ick [12] , ick [131 ,ick[143) ;

i=1;

/* process PLACE line */

if (! strncasecmp (ick[0], "PLACE", 5))

(strcpy(sym_name,ick[i++]);

if ((indx = fiad_place (sym_name)) >= 0)
^i

10

{

place [ indx] . act-name = ( char *)malloc ( strlen ( ick[i1)+1);

strcpy ( place [indx] . act_name , ick[i++]);

strcpy(owaer,ick[i++]);

tid = find_owner ( owner)

place [indxl . owner = tid

}

else

recInfo (globTid, "Could not find place ' %s' by name\a",

sym_name);

}

/* process TRANS line */

else if (! strncasecmp (ick[01, "TRANS", 5))

{strcpy(sym_name,ick[i++]);

strcpy(buff , ick[i++]);

if (! strncasecmp (buff, " SINGLE", 6))

{if ((infix = find-trans ( sym_name)) >= 0)

(trans[iadxl. act -name = ( char *) malloc ( strlen( ick[il) +1);

strcpy ( trans[indx] . act name,ick[i++]);

strcpy(owner,ick[i++]);

tid = find- owner ( owner)

trans[ind.4- owner = tid

}

else

recInfo (globTid, "Could not find trans ' %s' by name\n",

sym_name)

}

else if (! strncasecmp ( buff, " DOUBLE", 6))

{if ((indx = find -trans ( sym_name)) >= 0)

{trans[indx].act name = ( char *) malloc ( strlen( ick[i1)+1);

strcpy(transCindx] . act_name , ick[i++]);

— strcpy(owaer,ickCi++]);

tid = f ind_owner ( owner)

trans [indx] . owner = tid

trans[indx] • act_end_name = ( char *)malloc ( strlen ( ick[i3)+1);

strcpy ( trans[indxl . act_end_name,ick[i++]);

strcpy ( owner,ick[i++]);

tid = find-owner ( owner) ;

_ trans[indx] . end_owner = tid

recInfo (globTid, "Trans %s is split: %s , %s \a", trans [indx] . name,

trans [indx] . act name, trans [indx].act_end_name);

}

else

recInfo (globTid, "Could not find trans ' %s' by name\n",

sym_name)

}

/* process DISPLAY line */

else if (! strucasecmp ( ick[01, "DISPLAY", 7))

{net name = (char *) malloc ( strlen ( ick[i])+1)

strcpy (net-name, ick[i++])

if (i < imax)

{playTid = find_owner ( ick[il);

}

1

-Z^. - - —

- _.__
1

else

playTid = globTid; /* Default action */ 

/* ignore all other lines */

}

return (OK)

}

find-owner - find tid of owner of place or transition

TID-TYPE find-owner ( char *owner)

want to add " smarter" function than remembers already found owners 

return (msgTidquery ( globTid, owner))

}

C.8 msgs.c — Sends Various Messages

#include <X11/Xlib.h>

#include <X11 /Xutil.h>

#include <X11/1os.h>

#include <X11/Xatom.h>

#include <stdio.h>

*include <ctos.h>

*include <btsLib.h>

#include " Global-def.h"

*include " msg.h"

#include " Global_var.p"

extern TID-TYPE toTid;

extern char *myffame

#define FIRE-RATE (1)

* disp_set_tok()

* This routine builds and sends a message to the display

* indicating the new contents of a place.

void disp_set-tok ( int p-num)

{

UPDATES *pu 

HSG_TYPE ms¢

/* for local place, send msgs to displays */

if (place[n_numl.owner == globTid) 

{

/* get start of updates list

if ((pu = place [p_numl . update) __ HULL)

return
/* build message to displays */ 

msgBuild ( &msg, 0, globTid, MSG_SET_TOK, NULL, MS-NONE, MF_STANDARD) 

/* loop through list */

while (pu)

{

msg.dest = pu->tid

msg.data = ( void *) ( ( pu->num & OXOOOOSfff)

I (place [p-num].curr_token << 16))

msgSend ( &msg) ;

recInfo (globTid, "Set tokens =%2i in place ' %s.%s' on display %x\n",

I place [p_num] . curr_token, myName, place [p_numl.name,

pu->tid)

pu = pu->next

}

recInfo (globTid, "Set tokens =%2i in place '%s.%s'\n",

place [p_num].curr_token, myName, place [p_num].name) */

}

/* for remote place, send msg to owning player */

else

{

msgBuildSend ( place [p nua] . owner, globTid, MSG-ADD -TOKEN,

(void *) ( ( ( FIRE RATE << 16) & Oxfff10000)

I INDEX-FROM_ID (place[p_num] . id) ),

MS-NONE, MF_STANDARD) ;

recInfo (globTid, " %s: Add token to remote place I %s' in net %x\n",

}mylame, place [p_num] . name, place [p num] . owner) */

r

* disp_start _fire()

* This routine builds and : ends a message to the display

i

* indicating that a transitica has begun firing.

void disp_ start_fire ( iat t_num)

UPDATES *pu

MSG-TYPE msg

/* jet start of updates list */

it ((pu = traas[t_numl.update) -= NULL)

return ;

/* build message to displays */

msgBuild ( &msg, 0, globTid, MSG_START_TRANS, NULL, MS_NONE, MF_STANDARD)

/* loop through list */

while (pu) i {

if ((pu->which)&(T_START))

{

msg.dest = pu->tid

L
108

msg.data = (void *) pu->uum

magSend ( Amsg) ;

reclato ( globTid, " Start firing trans I %s.%s' on display %x\a",

myName, trans[t_num].name, pu->tid)

pu = pu->aext

}

reclafo (globTid, "Start firing trans 'Y,s As'\n", myfame, trans [t_num].name);

}

* disp_end_fire()

* This routine builds and sends a message to the display

* indicating that a transition has ended Siring.

void disp_end_fire (ins t_num)

{

UPDATES *pu

t

HSG_TYPE msg

t

/* get start of updates list */

if ((pu = trans[t_num].update) == NULL)

return ;

/* build message to displays */

msgBuild (&msg, 0, globTid, KSG_END_TRANS, BULL, KS_NONE, XF_STANDARD)

/* loop through list */

while (pu)

{

it ((pu->which)&(T_END))

{

msg.dest = pu->tid

msg.data = (void *) pu->u=

msgSend (kmsg)

reclnfo (globTid, "End Siring trans '%s.%s' on display Y•x\n",

myName, trans[t_num].name, pu->tid)

pu = pu->aext

}

reclnfo (globTid, "End firing trans 'ys.%s'\n", myName, trans [t_nvm].name);

}

C.9 var_mar x -- Manages the Variables for Local Functions

#include "Global_def.h"

struct var_entry var_table[HAX_VAR];

?.nt find_variable (char *name)

♦.^'^^^^tf
{

int i;

i=0;

while ((i<MAX_VAR)&&(var_table[il.ident_str))

{it ( !strcmp (name,var_table(il.ident_str))

return(i);

i++;

};

it (i<MAX_VAR)

{var_table[il.ident_str = ( char •) mal1oc(strlen(name) +1);

strcpy ( var_table [il.ident_str , name);

return(i);

};

return(-1);

}

int read_var ( int index)

{

return ( var_table [indexl . value);

}

void save_var(int index, int value)

{

var_table[indexl.value = value;

}

chat *get_var_name(int index)

{

return(var_table(indexl.ident_str);

}
APPENDIX D

Display Software

D.1 Makefile — The Display Makefile

# Makefile for test of UNIX version of CTOS

INC1 = /home/page/MCS/src/lib/btsLib

INC2 = /home/page/MCS/src/lib/msgLib

INC3 = /home/page/MCS/src/lib/ctosShell

INC4 = /usr2/testbed/CIRSSE/instilled/UNIX/h

INCS = /home/lefebvre/DEMOS/pnets/player

INC6 = /home/page/MCS/src/lib/recLib

INCT = /home/lefebvre/unix/ctos/domLib

n

CFLAGS = -0 -Wreturn-type -Wunused -Wsvitch -Wcomment

-Wshadov -Wpointer-arith -DMAKE_SUN4 -I$(INC1) -I$(INC2)

I$(INC3) -I$(INC4) -I$(INCS) -I$(INC6) -I$(INC7) - DOS_UNIX

BINDIR = /home/page/MCS/bin/sun4/

BTSLIB = $(BINDIR)btsErr.o $(BINDIR)btsSem.o $(BINDIR)btsGlobals.o

$(BINDIR)msgLib.o $(BINDIR)msgBCMem.o

PLAYDIR = /home/lefebvre/DEMOS/pnets/player/

RECDIR = /home/page/MCS/bin/suu4/

# List of targets...

all : disp_eh

# E.H. Tasks...

disp_eh: disp-eh.o Xsetup.o Xdray .o manip_net.o monitor.o Xinter.o \

$(PLAYDIR)load_net.o $(PLAYDIR)var_man.o

gcc $(CFLAGS) -o disp_sh disp_eh.o Xsetup.o Xdra y .o manip_net.o \

monitor.o Xinter.o $(PLAYDIR)tape.o $(FLAYDIR)load_uet.o \

$(RECDIR)recLib.o $(PLAYDIR)enable Suac.o $(PLAYDIR)post_func.o \

$(PLAYDIR)var_man.o $(BTSLIB) $(BINDIR)ctosShell.o \

-L/home/lefebvre/DEMOS/demos -L/home/lefebvre/unix/ctos/domLib \

-lcoord -ldom -1111 -Lm

disp_eh.o: disp_eh.c $(PLAYDIR)Global def.h

gcc -c $(CFLAGS) disp_eh.c -o disp_eh.o

Xsetup.o: Xsetup.c $(PLAYDIR)Global_def.h

gcc -c $(CFLAGS) Xsetup.c -o Xsetup.o

Xdray .o: Xdrao.c $(PLAYDIR)Global_def.h

gcc -c $(CFLAGS) Xdraa.c -o Xdray.o

manip_net.o: manip_net.c $(PLAYDIR)Global_def.h

gcc -c $(CFLAGS) manip_net.c -o manip_net.o

monitor.o: monitor.c

See -c $(CFLAGS) monitor.c -o monitor.o

110 

4
r

k

i

r

1

Xinter . o: Xinter . c $(PLAYDIR ) Global_def.h

gcc -c $(CFLAGS) linter -C -o Xinter.o

D.2 disp_eh.c — The Display Event Handler

File: disp_eh.c

Purpose: "Petri Net Display" event handler displays portions of net

Author: Joe Peck

revised: Don Lefebvre

Revised: 20 Aug'91

*wtt«w###w#*#««t*«#««#«##«#ww##^s*#**twt«t###w««#««««**####*«**«#*###ttt##«#***/

/*-------------------------------------- include : ilea --------------------

#include <X11/X?.ib.h>

#include <Xil/Xutil.h>

#include <X11/Xos.h>

#include <XIS/Xatom.h>

*include <stdio.h>

#include <signal.h>

#include <ctos.h>

#include <btsLib.h>

#include <recLib.h>

*include "msg.h"

*include " Global_def.h"

#include " Global_var.h"

!*-------------------------------------- global variables ------------ */

char root_name[2001;

char buff [200] ;

char *myName ;

char config_file [MAXLINE]

/*------------------------------- function prototypes --------------

STATUS load-net (char *aet_config_file, int type)

STATUS register-updates ()

void printPTinfo ()

void go-monitor 0;

MyTask ( disp-eh)

disp_ eh - subnet display for Petri Net

SYMBOLIC NAME: ( used to configure net)

RETURNS: 0 indicating processing complete

PARAMETERS: TID-TYPE myTid - task id of event handler

MSG-TYPE *msg - pointer to received message

int disp_eh( TID_TYPE myTid, MSG-TYPE *msg)

{

a.
static BOOL ready = FALSE

static int proc_id;

iat k, 1;

char databuff[101;

switch(msg->command)

{

case MSG_TASK_ARGS:

strcpy(buff. mag->data;;

break;

case KSG_PINIT:

globTid = myTid;

myName = msgMyTaskName (myTid)

sscanf(buff, 11s %s", root name, display name);

/* read display config file */

if (load net (root-name, CF_DISP) == ERROR)

recInfo (myTid, "Unable to load config file '%s'.disp",

root name) ;

msgAckAINIT (myTid)

msgipplicationExit (myTid)

recInfo (myTid "DISP: Loaded net I %s.disp'\n". root_name);

/* create Y window a.,

Yinit (myName, NULL, 0)

recInfo (myTid, "%s Initialized window\n", mylame)

/* initialize variables */

visible layer = Oxffff;

tags -on = 1;

scale = 1.0;

offset_x = 0.0;

offset_y = 0.0;

/* scale the net */

rescale_net(scale, offset -x, offset-y);

recInfo (myTid, "%s Scaled net\a", myName) */

I

sleep(2);

/* display the net */

dray vhole_net();

recInfo (myTid, "%a Displayaa uetWI , myffame)

/* ready s TRUE */

break

case KSG_AINIT:

register updates () ;

/* Fork off the process to monitor input */

proc_id = forkO; 

if (proc_id == 0) /* monitor process */

go-monitor () ;
break ;

case MSG_AEXEC:

recInfo (myTid, "%s Received AEXEC\n", myName)

priatPTinfo O */

break

case HSG_DRAW WHOLE-NET:

recInfo (myTid, "%s Received DRAW_HHOLE_NET\a myName)

drav_ahole_net();

break;

case MSG_SIT_ON_HANDS:

recInfo (myTid. "%a Received SIT_ON_RANDS\n". myName)

j sleep(S);

break;

case MSG SET_TOK:

recInfo (myTid, "%s Received SET_TOK\n", myName) */

set token(msg->source, (int)msg->data);

break;

case MSG-START-TRANS:

!* recInfo (myTid, "%s Received START_TRANS\n", myName) */

r mark_trans(msg->source, (int)msg->data);

break;

I

case MSG-END-TRANS:

recInfo (myTid, /.s Received END_TRANS\n", myName) */

unmark_trans(msg->source, (int)msg->data);

i break;

1

case MSG-TOGGLE-TAGS:

recInfo (myTid, "%s Received TOGGLE_TAGS\u", myName) */

tags on

drag-whole-net(;

break;

case MSG_VISIBLE:

recInfo (myTid, Its Received VISIBLE\n", myName) */

visible-layer = (int)msg->data;

draw-whole-not(;

break;

case MSG-SHIFT-DISPLAY:

recInfo (myTid, "%s Received SHIFT_DISPLAY\n", myName) ; */

offset -x += („ _,it)HORI SHIFT((int)msg->data);

offset_y += 1",tt)VERT_SHIFT((int)msg->data);

rescale_net(scale, offset -x, offset-y);

drag-whole_net();

break;

r
I .

case MSG-CHANGE-SCALE:

recInto ( myTid, "%s Received CHANGE_SCALE\n", myName) */

scale +s (float)( ( in';)(msg->data)*SCALE_FACTOR);

it (scale <n 0.0)

scale s 0.1;

rescale_net(scale, ofiset_x, offset_y);

dray vhole_nat();

break;

case MSG-SELECT-PLACE:

recWo (myTid, "Y,s Received SELECT_PLACE\n", myName)

1 • GET_INDEX((int)msg->data);

switch ( GET_BUTTON( ( int)msg->data))

{case 1:

recxnfo ( globTid, "Should add a token\n");

msgBuildS and ( place W. o%mer, myTid,

MSG_ADD_TOKEN,

(void *) ((INDEX_FROM_ID(place Ell. id)

k 0x00002111) 1 (1 << 16)),

MS-NONE, MF_STANDARD);

break;

case 2:

re0rompt (my?id,databull, " Place %s: Enter token quantity:

placs [ll.name);

if (sscant ( databuli,"%d",kk))

it (k>=0)

msgBuildSend(place [ll.owner, myTid,

MSG_SET_TOK,

(void *) ((INDEX_FROM_ID (place Ell. id)

k Ox00002ii1) I (k << 16)),

MS-NONE, MF_STANDARD);

break;

case 3:

w recInto (globTid, "Should subtract a token\n");

msgBuildSend ( place [ll.oaner, myTid,

MSG-SUB -TOKEN,

(void *) ((INDEX_FROM_ID (place Ell Ad)

k OXOOOOSSit) I (1 << 16)),

MS-NONE, MF_STANDARD);

break;

break;

case MSG_SELECT_TRANS:

recInlo (myTid, "%s Received SELECT_TRANS\n", myHame)

1 = GET_INDEX( ( int)msg->data);

it (mode an SINGLE-STEP)

{msg3uildSend(trans[ll.ovnar, myTid,

MSG_CHK_FIRE_TRANS,

(void *)I1DE1 _FROM_ID ( trans [ll.id),

MS_NONE, MF_STANDARD);

break;

case MSG-SET-MODE.

reclnlo (myTid, "%s Received SET_MODE\n", myNama)

mode s (int ) msg->data;

break;
^ IIJ

case MSG_PTERM:

recInfo (myTid, "%s Received PTERM \a", myName) #/

kill ( prcc_id , SIGKILL);

break;

}

/* until X window refresh works, redraw everything */

l

if (ready zz TRUE)

{

draw-whole_net(); !/

usleep(500)

return (msgDefaultProc (myTid, msg))

}

printPTinfo - print place g transition information

void printPTinfo O

{

int i

if (!stracasecmp (myName, "DISP_A", 6))

sleep (3) ;

else if (!strncasecmp (myName, "DISP_B", 6))

sleep (4)

else if (!stracasecmp (myName, "DIS? C", 6))

sleep (5)

recInfo (globTid, '• \nNet game: %s\n", myName)

recInfo (globTid, "PLACES Mil \n", num_pl)

for (i=0; i<num_pl; i++)

recInfo (globTid, "\t%6s %8x %4x \n", place[il.name,

place[il.id , place[il.owner)

}

recInfo (globTid, "TRANSITIONS C/.il\n nun tr)

for (i=0; i<num-tr; i++)

recInfo (globTid, "\t%6s %8x Ux W', trans[il.name,

trans[il.id , trans [il.owner)

register-updates - sends request msgs to register display updates

STATUS register-updates ()

{

int

REG_RE."IOTE *ps

/* send msg for each place */

for (i=e; i<num_pl; i++)

{

- 
ps = (REG _REMOTE *) malloc ( sizeof ( REG_REMOTE))

strcpy ( ps->sym_name. pla,e [ il.name) ;

strcpy ( ps->act name, place(il . act_name)

ps->type = PLACE NODE

ps->id - i ;

place [il.id = msgBuildSend (place[il.ovner, glob

(void *) ps, sizeof (REG_REMOTE),

MF_REPLYWAIT)

}

/* send msg for each trans */

for (i=0; i<nnm_tr; i++)

{

ps = (REG_REMOTE *) malloc ( sizeof (REG-REMOTE))

strcpy • (ps->sym_name, trans[il . name) ;

strcpy (ps->act name, trans[il . act name)

ps->type = TRANS-NODE

ps->id = i ;

if.(transCil.end_owner == HULL)

{ps->vhich = T_BOTH;

trans [i] . id = msgBuildSend (trans [i].owner, globTid,

MSG_REGISTER_UPDATE,

(void *) ps, sizeof (REG_REMOTE)

KF_REPLYWAIT)

}

else

{ps->vhich T_STAP.T;

trans[il . id = msgBuildSend (trans [il . owner, globTid.

MSG-REGISTER-UPDATE,

(void *) ps, sizeof (REG_REMOTE),

MF_REP:YYAIT) ;

ps = (REG_REMOTE *) malloc ( sizeo*_ ( REG_REMOTE))

strcpy (ps->sym_name, trans[il.name) ;

strcpy (ps->act_name, traas[il.act_end_name)

ps->type = TRANS-NODE

ps->id = i ;

ps->vhich = T-END;

trans [il . end-id = msgBuildSend (trans [il . end_owner, globTid,

MSG-REGISTER-UPDATE,

(void *) ps, sizeof (REG_REMOTE),

MF_REPLWAIT)

} };

return (OK)

}

D.3 Xdraw.c — Performs All X-Drawing Actions

*include <X11/Xlib.h>

#include <Xll/Xutil.h>

#include <Xll /Xcs.h>

#include <X11 /Xatom.h>

#include <stdio.h>

*include <ctos.h>

#include <btsLib.h>
11 

*include "recLib.h"

#include " Global_de2.h"

i *include "msg.h"

' #include " Xdraw.p"

ext-ira Display *display;

extern Window window;

extern GC gc;

extern XFontStruct *act_iont;

extern struct Place *place;

extern struct Trans *trans;

extern int num_pl, num_tr;

^ extern int radius, radius2, diameter;

extern int tags on, rates on, visible_layer;

1

extern struct tape_node *head;

extern char *tind_tape_aame();

struct tape-entry

_ {int id;

char * ident_str;

struct tape-node

{int id;

struct tape-node *next;

/***:::**.*__*****:**:s•****:*:s*ssssss***sss*s**s********s**s************

* draw_whole_net()

* This routine clears the display window and redraws the

* Petri net. Layers are dealt with by the called routines.

void draw-whole-net(void)

{

int

XC1earWindow (display, window);

draw tape();

/* prints( "Total places: %d\n",num_pl); */

/* printt( "Total transitions: %d\n",num_tr); */

le

^_. for (i=O;i<num_tr;i++

{draw_trans(i);

it (tags-on)

j drau_trans_tag(i);

if (rates-on)

draw_trans_rate(i);

draw_ares(i);

it (trans(i7.2iring == TRUE)

highlight _i;rans(i);
};

for (i=0;i<num_pi;l++)

{draw_place(i); /* this is reduntant: dra g token redraws the place #/

draa _token(i);

if (tags-on)

d-aw_place_tag(i);

};

XFlush ( display);

}

# set-token(

« This routine sets the number of tokens in a place and

redisplays the place.

void set token(TID TYPE from, int data)

{

int p num, num_tok;

num_tok = (data&Oxf*_ff0000)»16;

p_num = datakOxffff;

place[p num].curr_token = num_tok;

draw_token(p_num);

XFlush(display);

}

/*##ss##RS###is#RR#ss##R#s##«ss#ss###s##si#*ss#****#######*####*##*#s*ssss

* mark-trans(

* This routine highlights a transition to indicate that

* it has started to fire.

void mark_trans(TID_TYPE from, int data)

{

int t num;

t_num = datakOxffff;

if (++trans [t_num] . firing == 1)

{highlight trans(t_num);

XFlush(display);

}

/##**R«R#RR«R#«R#RR«RR*#####*ft*##*##****#***###***w****##ws*#*#+k***R*+Ic*ss*

n—ark trans()

# This routine unhighlights a transition to indicate that

* a transition has completed firing.

void unmark_trans (TID_TYPE from, int data)

{

int t_num;

t_num = data&Oxffff;

if (trans [t_num] .firing !z 0)

if (--trans [t_num] . firing == 0) /* just reached zero #/

{h ighlight -trans ( t_num);

XFlush ( display);

118
1

* valid-layer(

* This routine checks if any of the indicated layers are

* currently enabled for display.

int valid_layer(int layer)

{

return (visible layer It layer);

}

/»»ww*ww»*»wwww******w***»*w*»»***w*»»**»w***w**w***»***s**w******»*******

* drav_place()

* This routine draws the indicated place. As a side effect,

* it erases any tokens that were already drawn.

*I

void draw-place(int i)

{

if (valid_layer (place [ i].layer))

{draw_type ( ERASE);

ZF'illArc (display, window, Sc. place [i].x_loc - radius,

place[i].y-loc - radius,

diameter, diameter, 0. 360*64);

drav_type(DRAW);

RDrawArc(display, window, gc, place [ i].x_loc - radius,

place [i].y_loc - radius,

diameter, diameter, 0, 360*64);

/* priatf( "Draving place Yd at Y.d ,Y.dk n",i,place[i].x_loc, place [i].y_loc); *I

}

* draw token()

* This routine redraws the indicated place to erase the old

* tokens, then redraws all of the tokens in the place. Up to

* nine tokens may be drawn, thereafter digits are used. The

* token size is changed based on the number of tokens in the place.

void drav_token(int i)

{

char buff [5] ;

draw_place(i);

if (valid_layer(place[il.layer))

{switch(place [ il.curr_token)

{case 0: break;

case 1:

draw- 1_tok (place[i] . x-loc, place [il.y_loc,L);

break;

case 2:

draw_1 tok (place [i].x_loc - radius/2, place [ il.y_loc,L);

drav_1_tok(place[i].x_loc t radius/2, place[il.y_loc,L);

break;

}

/***»wwwww*ww*wwww*w****w»wwww»w»»»»ww*w»»www»wwww*»w**»***»*****w»*ww***w
12

case 3:

drav_1_tok(place[i].x_loc - radius/2, place[i].y_loc + radius/2,L);

drav_1_tok (place [i].x_loc + radius/2, place[i].y-loc + radius/2,L);

draw_ 1_tok(place[i].x_loc, place[i].y_loc - radius/2,L);

break;

case 4:

draw_1_tok(place[i].x_loc - radius/2, place[i].y-loc + radius/2,M); 

draw_1_tok (place [i].x-loc + radius/2, place[i].y_loc + radius/2,M);

draw_ 1_tok (place [i].x_loc - radius/2, place[i].y_loc - radius/2,M);

draw_ 1_tok (place [i].x_loc + radius/2, place[i].y_loc - radius/2,M);

break; 

case 5:

draw- 1_tok (place [i].x_loc - radius/2, place[i].y_loc + radius/2,M);

draw_1_tok (place [i].x_loc + radius/2, place[i].y_loc + radius/2,M);

draw_! tok (place Cil .x_loc - radius/2, place[i].y_loc - radius/2,M);

draw_ 1_tok (place [i].x_loc + radius/2, place[i].y_loc - radius/2,M);

draw_! tok(place[i].x_loc, place[i].y -loc,M); 

break;

case 6:

draw_1_tok(place[i].x_loc - radius/2, place[i].y_loc + radius/2,S);

draw_1_tok (place [i].z_loc + radius/2, place[i].y_loc + radius/2,S);

draw_1_tok(place[i].x_loc - radius/2, place[i].y_loc - radius/2,S);

draw - 1 -tok (place [i].x_loc + radius/2, place[i].y_loc - radius/2,S);

draw_i_tok(place[i].x_loc, place[i].y -loc + radius/2,S);

draw_ 1_tok (place [i].x_loc, place[i].y_loc - radius/2,S);

break;

case T:

draw_1-tok (place [i].x_loc - radius/2, place[i].y_loc + radius/2,S);

draw_1_tok (place [i].x_loc + radius/2, place[i].y_loc + radius/2,S);

draw_! -tok (place [i].x_loc - radius/2, place[i].y_loc - radius/2,S);

draw_ 1_tok(place[i].x_loc + radius/2, place[i].y_loc - radius/2,S);

draw_! tok(place[i].x_loc, place[i].y_loc + radius/2,S);

draw_1_tok(place[i].z loc, place[i].y loc - radius/2,S);

draw- 1_tok(place[i].x_loc, place[i].y_loc,S);

break;

case 8:

draw_! tok(place[i].x-loc - radius/2, place[i].y_loc + radius/2,S);

draw_1_tok (place [i].a loc + radius/2, place [i].y_loc + radius/2, S);

draw_1_tok (place [i].x_loc - radius/2, place[i].y_loc - radius/2,S);

draw_! tok(place[i].x_loc + radius/2, place[i].y_loc - radius/2,S);

draw_! tok(place[i].x_loc, place[i].y_loc + radius/2,S);

draw_1_tok (place [i].z loc, place[i].y_loc - radius/2,S);

drav_1_tok(place[i].x-loc - radius/2, place[i].y_loc,S);

draw_1_tok(place[i].x-loc + radius/2, place[i].y_loc,S);

break;

case 9:

draw_1_tok(place[i].x-loc - radius/2, place[i].y_loc + radius/2,S);

draw_ i_tok (Place [i].x-loc + radius/2, place[i].y_loc + radius/2,S);

drav_1_tok(place[i].x-loc - radius/2, place[i].y_loc - radius/2,S);

draw- i_tok(place[i].x_loc + radius/2, place [i].y_loc - radius/2, S);

draw_1_tok(place[i].x_loc, place[i].y_loc + radius/2,S);

draw_1_tok(place[i].x_loc, place[i].y_loc - radius/2,S);

dray- 1_tok(place[i].x_loc - radius/2, place[i].y_lo

dracr_1-tok (place [i].x_loc + radius/2, place [i].y_loc,S);
draw_ i_tok ( place [i].x_loc, place[i].y_loc,S);

break;

default: sprintf ( buff, "%d", place[i].curr_token);

XDrawString ( display, window, gc,

place E i].x- loc - XTextWidth ( act_fout, buff. strlen ( buff))/2

place[i].y_loc + ( act_font->ascent)/2,

buff, strlen ( buff));

break;

}

* draw_1 token()

i » This routine draws a single token at the given location and

t' * size.

t void draw_ i_tok ( int x , int y, float size)

{

XFillArc (display, window, gc, x - max((int)(radius *size ) , 2)/2,

y - max((int)(radius*size),2)/2,

max((int)(radius*size),2), max((int)(radius*size),2),

0, 360*64);

}

i * draw-place tagO

* This routine draws the tag associated with the given place.

void draw_place_tag(int i)

{

if (valid_layer ( place [i].layer))

j XDrawString ( display, window, gc, place [ i].tag- x, place [i].tag_y,

place [i].name, strlen ( place[i]- name));

}

/r»*****»»»r»»»»r**r**»rrrrrr»***»*rr»*r»r*»**»»»»r»»*»»**»»*** *r»»**r*r**

* draw trans()

* This routine draws the given transition. The line type used

* indicates the type of transition, and the correct orientation

* is used as well.

void draw_trans(int i)

{

if (valid- layer ( trans [i].layer))

(set_line (trans [i].kind);

t

swltch(trans[1].orient)

{case 0: XDrawLine (display, window, ge, trans[i] . x_loc - rad us,

traas[i] . y_loc, transCi] . x_loc + radius, trans[i].y_loc);

break;

case 1: XDrawLine ( display, window, gc, trans[i] . x_loc,

trans[i].y-loc - radius, trans[:;.-._loc,

trans [i].y_loc + radius);

break;

case 2: XDrawLine ( display, window, gc.

trans [i].x_loc - radius2,trans[i] . y_loc a radius2,

W«r
12

trans[i].x_loc + radius2, trans [il.y_loc + radius2);

break;

default :

break;

set_line(DEFAULT);

}

* draw_trans_tag()

* This routine draws the tag associated with the given transition.

void draw_trans_tag(int i)

{

if (valid_layer (trans [il.layer))

XDravString(display, window, gc, trans[il.tagg_x, trans[il.tag_y,

trans[il.name, strlen(transCil.name));

}

* draw_trans_rateO

* This routine draws the rate associated with the given transition.

void draw_trans_rate(int i)

{

char butf[MAXLINE];

if (valid_layer(trans[il.layer))

{sprintf(buff, "'/,f", trans[i].fire_rate);

XDrawString(display, window, gc, trans[il.rate_x, trans [il.rate_y.

buff, strlen(buff));

* highlight trans()

* This routine draws an inverted circle over the given transition,

* changing it's current display state.

void highlight trans(int i)

{

if (valid_layer(trans[il.layer))

{draw_type(INVERT);

XFillArc(display, window, gc, trans[il.x_loc - radius,

tran::[il.y_loc - radius,

diameter, diameter, 0, 360*64);

draw_type(DRAW);

}

» draw-arcs(

* This routine draws the input, output and inhibitor arcs for

* the given transition.

void d°:o-xw_ares!int i)
123

{

struct Arc •arc_a;

struct Arc point +arc_point_a;

int x, y;

arc_a = trans[il.inp_arc;

while (arc_a)

{it (valid_layer(arc_a->layer))

{x = arc_a->x_st art;

y = arc_a->y_start;

arc_point_a = arc_a->arc_points;

j while(arc_point_a)

l{XDrawLine(display, window, gc, x, y,

arc-point_a->x, arc-point-a->y);

x = arc_point_a->x;

y = arc_point_a->y;

arc_point_a = are_point_a- >next;

XDrawLine(display, window, gc, x, y, arc_a->x_end, arc_a->y_end);

XDrawLine(display, window, gc. arc_a->arrow->x0, arc_a->arrow->y0,

arc_a->arrow->xl, arc_a->arrow->yl);

XDrawLine ( display, window, gc, arc_a->arrou->x0, arc_a->arrow->y0,

arc_a->arrow->x2, arc_a->arrow->y2);

j XDrawLine(display, window, gc, arc_a->arrow->xi, arc_a->arrow->y1,

arc_a->arrow->x2, arc_a->arrow->y2);

= arca->next;

f

arc_a

arc_a = trans[al • out_arc;

while (arc_a)

{it (valid_layer(arc_a->layer))

{x = arc_a->x_start;

y = arc_a->y_start;

E arc_point_a = arc a->arc_points;

while(arc_point_a)

` {U.nrawLine(display, window, gc, x v y,

a:c_point_a->z. arc-point_a->y);

x = a_c_point_a->x;

y = arc_point_a->y;

arc_point_a = arc_point_a->uext;

XDrawLine(display, window, P. x, y, arc_a->x_end, arc_a->y_end);

=(' XDrawLine(display, window, gc, arc_a->arrow->x0, arc_a->arrow->y0,

!! arc_a->arrow->x1, arc_a->arrcw->yl);

XDrawLine(display, window, gc, arc_a->arruw->x0, arc_a->arrow->y0,

arc_a->arrow->x2, arc_a->arrow->y2);

XDrawLine(display, window, gc, arc_a->arrow->xl, arc_a->arrov->yl,

a

1

arc_a->arrow->x2. arc_a->arrow->y2);

arc_a = arc_a->next; r }:

arc_a = trans [il . inh-arc;

while (arc_a)

{it (valid_layer(arc_a->layer))

{x = arc_a->x_start;

y = arc_a->y_start;

arc-point a = arc_a->arc_points;

while(arc_pcint_a)

{XDrawLine(display, window, gc, x, y,
I

arc_point_a->x, arc_point_a->y);

x arc_point_a->x;

y arc_point_a->y;

arc_point_a = arc_point_a->naxt;

XDrawLine(display, window, gc, x, y, arc_a->x_end, arc_a->y_end);

XFillArc(display, window, gc, arc_a->arrow->xO - radius/3,

arc_a->arrow->y0 - radius/3,

diameter/3, diameter/3, 0, 360*64);

arc_a = arc_a->next;

}

#define LEFT-EDGE 10

*define TOP -EDGE 10

*define WIDTH 1024

*define HEIGHT 30

#define MAX_CIIAR 10

draw taps()

{

struct tape-node *tmp;

char *name;

int offset, height, shift, i=1;

draw_type(ERASE);

XFillRectangle(display, window, gc, LEFT-EDGE, TOP_EDGE-1,

WIDTH, HEIGHT);

draw_type(DRAW);

XDrawString(display, window, gc, LEFT_EDGE, TOP_EDGE+act_font->ascent,

"TAPE:", S);

tmp = head;

shift = act_font->max bounds.width;

offset = MAX_CHAR*act font->max_bounds.width;

height =act_font->max_bouads.ascent+act_fout->max_bounds.deseent;

while (tmp )

{name = find_tape_name(tmp->id);

XDrawRectangle(display, window, gc, LEFT_EDGE+(i)*offset-shift,

TOP-EDGE-1, offset, height+2);

XDrawString(display, window, gc, LEFT_EDGE+(i++)*offset,

TOP_EDGE+act_fout->ascent,

name, strlen(name));

Up = tmp->next;

}

DA Xsetup.c — Initializes the Windowing System

#include <X11/Xlib.h>

#include <X11/Xutil.h>

#include <X11/Xos.h>

#include <X11/Xatom.h>
*include <stdio.h>

#include "recLib.h"

#include "Global_def.h"

#include "Global_var.p"

#define BORDER 3

/*----------------------------- function prototypes --- -----------__--__*/

void getGC(Windog window, GC *gc);

void load_fout(void);

void set_font(int i);

* Xiait()

* This routine initializes the X-variables and opens

* a window.

void Xinit(char *nets name, char *argv Q , int argc)

{

int x, y;

unsigned int width, height, display width, display_height;

char *window_name = nets_name;

char *icon_name = nets-name;

XSizeHints size hints;

XWKHints wmhints;

XClassHint class-hints;

XTextProperty windowname,iconname;

char *program_name = "Display";

/* ccanect to X server */

it ((display = XOpenDisplay(display_name)) _= NULL)

{recInto(globTid,"Net %s cannot open display %s\n", nets name,

nisplayffame(display_name));

exit(-i);

/* get screen information */

screen_num = DefaultScreen(display);

display width = DisplayWidth(display, screen_num);

display-height = Displayffeight(display, screen_num);

/* set desired window settings */

x = 0;

y = 0;

width = display_vidth/2;

height = display-height/2;

/* create the window */

window = (Window *)XCreateSimpleWindow(display,

RootWindow(display,screen_aum), y,

width, height, BORDER, B1ackPixel(display, screen-uum),

WhitePixel(display, screen_num));

/* provide hints for the window manager */

size_hints.flags = PPosition I PSize;

/* setup the window and icon name */
1

f'

it (XStri.ngListToTextProperty(tvindoQ _asme, 1, tvindovnams) an 0) 

{lpriatt(stderr, "Net ''/,s tailed structure allocation for wiadoaaame . \a•',

nets name);

exit(-1);

' it (XStringListToTextProperty(kicon_name, 1, kiconname) an 0)

t {fpriatt(stderr,"Net ys tailed structure allocation for icouname.\n", 

nets-awe); 

exit(-1): 

wm_hints . initial_state = MormalState;

wm_hints . input = True; 

wm_hints . tlags = StateBint I InputEint;

class _hints.res_name = program-name;

class_hints . res_class = program-name;

XSetWMProperties(display, (int)vindov, &vindowname, kiconname,argv,argc,

ksize_hints, kvm_hints, kclass_hints);

/* set desired event types */

XSelectInput(display, (int) window, ExposureMash I KeyPressMask ( 

ButtouPressMask I StructurelotifyMask);

/* load fonts */ 

load fonts O ;

/* create GC

get=vindow, kgc);

/* display the window */

XM-tpWindov(display, (int) window);

XFlush(display);,

}

* getGCO 

* This routine creates the graphics context ( GC) and

* sets up the default paramete

*/

void getGC ( Window window, GC *gc)

unsigned long valuemask = 0;

XGCValues values; 

int line style = LineSol'.d;

int cap style = CapRound; 

int join-style = JoinRound;

int dash cftsat = 0;

*gc = XCreat eGC (display, window, valuemask, kvalues); 

set_font(i); 

XSetFoat(display, *gc, act_tont->tid); 

XSetForeground(display, *Sc, BlackPixel(display,screea_num));
121

XSetLineAttributes(display, *gc, line -width, line_style,

cap-style, join-style);

}

* set-line()

* This routine changes the line type depending upon

* the type of transition to be drawn.

void set_line(int i)

{

switch(i)

{case IHH: XSetLineAttributes ( display, gc, line width*3/2, LineSolid,

CapButt, JoinRound);

break;

case DET: XSetLi. neAttributes(display, gc, radius /2, LineSolid,

CapButt, JoinRound);

break;

case EXP: XSetLineAttributes ( display, gc, radius /2, LineSolid,

CapButt, JoinRound);

break;

default: XSetLineAttributes ( display, gc, line width, LineSolid,

CapButt, JoinRound);

}

* load-!oats()

* This routine loads all of the fonts that the display

* needs to show tokens, tags, etc.

void load-fonts()

it M fout [03 = XLoadQueryFont ( display, " Sxs")))

{fprintt ( stderr, "Cannot load SxC font\n");

exit(-i);

if (!(font [13 = XLoadQueryFoat ( display, " 6x10")))

{fprintf ( stderr, "Cannot load 6x10 font\n");

•i exit(-i);

it M font[23 = XLoadQueryFoat ( display, " Sxl3l')))

{fprintf ( stderr, "Cannot load Sx13 font\n");

exit(-1);

if W fout[33 = XLoadQueryFout ( d4splay, "3x1S"))) 

{fprintf ( stderr, "Cannot load 9x15 font\n");

exit(-1);

* set-font()

* This routine changes the current font in use.
128

void set -foat(int i) t

act-font = font[i];

XSetFont(display, gc, act-foot->fid);

}

* draw-type()

* This routine changes the drawing mode.

void draw-type(int mode)

{

switch(mods)

{case ERASE:. XSetForeground(display, gc, Whit ePixel(display,screen-num));

XSetFunction(display, gc, GXcopy);

break;

case DRAY: XSetForeground(display, gc, HlackPixel(display,screen-num));

XSetFunction(display, gc, GXcopy);

break;

case INVERT: / s XSetForeground(display,gc, YhitePixel(display,screen-num));

XSetFunction(display, gc, GXxor); */

XSetFunction(display, gc, GXinverr:);

break;

default: break;

}

D.5 manip-net.c — Performs Scaling and Shifting of Display

*include <X11/Xlib.h>

*include <X11/Xutil.h>

#include <XI1/Xos.h>

*include <X11/Xat6m.h>

*include <stdio.h>

*include <math.h>

*include "Global-def.h"

#include "Global-var.p"

• modify-end-potnt(arc,x,y)

struct Are *arc;

int x,y;

{

int dx, dy;

double angle;

dx s x - arc->x-end;

dy = y - arc->y-end;

if (dx — 0)

{if (dy >0)

arc->y-end += radius;

also

arc->y-end -a radius;

return;
if (dy == 0) 

€if (dx >O) 

arc->x,end +r radius ; 

else 

arc->x,enc? -= radius ; 

return; 

1; 

angle = atan((double)dy/dx); 

if (dx > 0) 

else 

{arc->x-end -= radiusrcos (angle) ; 

=c->y-erid -* radius*sin(agle); 

1; 

modif y,arrov(arc ,x, y) 

struct Arc *arc; 

int x,y; 

€ 

int dx, dy, xo, yo; 

double angle; 

ZtIuSt Arrowhead *-; 

iur = (struct Arrowhead *)malloc(sfzeof (stmct Arrowhead) ) ; 

a,c->=ou = '1. arr ; 

I' els o 

ixo = arc->x,start; 

YO = arc->y,stan; >: 

M:->xO = to; 

arr->yo = pa; 

dx = x - x0; 

dy = y - yo; 

if (dx == 0) 

<if !dy >O) 

ang1.e = -n,PI/2; 

else 

angle = n,PI/2; 

3 

else 

€if (dy == 0) 

angle = 0.0; 

else 

angle = atan( (double)dy/dx) ; 
if (dx > 0)

{arr->xl xO + radius*cos(aagie+ANG);

arr->yl yO + radius*sin(angle+ANG);

arr-n2 xO + radius*cos(angle-ANG);

arr->y2 yO + radius*sin(angle- M);

}

else

{arr->xl xO - radius*cos(angle+ANG);

ar->y t YO - radius*sin(angle+ANG);

arr->x2 xO - radius*cos(angle-ANG);

ar->y2 yO - radius*sin(angle-ANG);

}

modify-end-circle(arc)

struct Arc *arc;

{

int x, y;

struct Arrowhead *arr;

ar = art->arrow;

arr->xO = (2*arr->xO + arr->xl + arr->x2)/4;

arr->y0 = (2*ar->y0 + arr->yl + arr->y2)/4;

}

rescale_net(scale,offset_x,offset_y)

float scale, offset_x, offset._y;

{

int i, x, y, xi, yi;

struct Are *arc_a, *arc b;

struct Arc point *arc_point_a, *arc_point_b;

diameter = (int)DIAMETER*scale;

radius = d4ameter/2;

radius2 = (int)(radius/1.414);

for (i=O;i<num_mp;i++)

{mpar[il.tag_x = X_IN TO_PIX(mpar[il.tag_x_in);

mpar[il.tag_y = Y_IN_TO_PIX(mpar[i].tag_y_in);

};

for (i=O;i<aum_rp;i++)

{rpar [il.tag_x = I IN TO _PIX(rparCi] . tag_x_in);

rpar [i].tag_y = Y_IN_TO_PIX (rpar[i] . tag_y_in);

};

for (i = O;i<aum_pl;

{place [ i].x_loc

place [ il.y-loc

place(il.tag x

place[il.tag_y

};

L++)

= X_IN_TO_PIX(place [i].x_loc_in);

= Y_IN TO_PIX(place [ i].y_loc_in);

= I_IN TO_PIX(place[i].tag_x_in);

= Y_IN_TC_PIX (place[i] . tag_y_in);

for (i= O;i<num_tr;i++)

{trans[i] . x_loc = X_IN_TO_PIX(trans[i].x_loc_in);

trans[il.y-loc = Y_IN_TO_PII(trans[i].y_loc_in);

trans[i] . tag_x = X_IN_TO_PIX (trans [i].tag_x_in);

trans [ il.tag_y = Y_IN _TO_PIX ( trans Cil.tag_y_in);
1

trans

[ i].rate

_x - X_IN

_TO_PIX

( trans[il.rate_x_in);

trans[i] . rate_y j Y_IN

_TO_PIX

( traas[i].ratea

►_in);

arc_a = trans[i] . inp_arc;

vhile

( arc_a)

(x = arc_a-

>x_start = trans[i].x_loc;

y = arc_a->y start = trans[i] . y_loc;

arc_a->x_end = place[arc_a-

>place] . x_loc;

arc_a-

>y_end = place

[arc_a-

>place] . y_loc;

if (arc_point_a = arc_a->arc_points)

(xi = X_IN

_TO_PII

( arc_point_a->x_in);

yi = Y_IN_TO PIX(arc_point

_a->y_i.n);

}

also

(xi = arc

_a->x_end;

yl = arc_a->y_end;

};

ahile

( arc_point_a)

(x = arc

-point -a-

>x = X_IN_TO PIX

( arc_point_a->x_in);

y = arc_point

_a->y = Y_IN TO_PIX(arc_point_a->y_ia);

arc_point

_a = arc_point

_a->next;

};

modity_end_point(arc_a,x,y);

modify_arroc(arc_a,xI.yI);

arc_a = arc_a->next;

arc_a = trans[i].out_arc;

vhile(arc_a) ` {x = arc_a->x_start = trans[i].x_loc;

y = arc_a->y_start = trans[i] . y_loc;

arc_a->x

_end = place[arc_a->place] . x_loc;

arc_a-

>y_end = place[arc

_a->placel . y_loc;

arc_point

_a = arc_a->arc

_points;

vhile

( arc_point_a)

(x = arc

_point_a->x = X_IN_TO_PIX

( arc_point_a->x_in); ! y = arc_point a->y = Y_IB TO_PIX(arc_point_a->y_in);

arc_point

_a = arc_point_a->next;

};

modity_end_point(arc a,x,y);

modi:fy_arrov(arc_a,x,y);

arc_a = arc_a->next;

f

}; ! arc_a = trans[i]-inh_arc; { Ahile(arc_a)

(x = are_a->x_start = trams [i].x_loc;

y = are_a->y_start = trans[i].y-lor; j arc_a->x_end = place[arc_a->place].x_loc;

arc_a->y_end = place[arc_a->place].y_loc;

it (arc_point_a = arc_a->arc_points)

i (xl _ X_IN_TO_PIX(arc_point a->x_in); a }yi Y_IN_TO_PIX(arc_point_a->y_in);

else

(xl = arc_a->x_end;

yl = arc_a->y_end;

};

while

( arc_point_a)

(x = arc point a->x = X_IN_TO_PIX( arc_point_a->x_in);

y = arc_point_a-

>y = Y_IN_TO_PIX

( arc_point_a->y_in);

L
arc_point_a a arc point-a->next;

modify_end_point(arc_a,x,y);

modify_arrov(arc-a,x1.y1);

modify end-circle(arc_a);

arc_a = arc a->next;

line_aidth = 0;

if (diameter < 20)

set_font(0);

also

if (diameter < 26)

set_font(1);

else

if (diameter < 35)

{set lont(2);

line_aidth = 2;

}

else

{set-font(3);

line width = 3;

}

}

D.6 monitors — Processes X-Window Events

#include <X11/Xlib.h>

*include <X11/Xutil.h>

#include <Xli/Xos.h>

#include <X11/Xatom.h>

#include <X11/keysym.h>

#include <stdio.h>

#include <ctos.h>

#include "Global_def.h"

*include "Global_var.p"

#incude "msg.h"

extern. Display *display;

extern radius;

void go monitor()

{

int id, dist;

XEvent report;

XKeyEvent *rep_ptr;

char buff C5] ;

char buf [101;

Hey3ym key;

int f;

MSG TYPE msg;

int shift_hor=0, shift_ver=0, siue_chng=0, rescale = FALSE;

while (1) {

XNextEvent(display, #report);

switch (report.type) {

case Expose:
/* unless this is the last contiguous expose,

* don't draw the window */

if (report.xexpose.count != 0)

break;

1 msgBuildSend (globTid, globTid, MSG-DRAW-WHOLE-NET,

NULL, MS NONE, MF_STANDARD);

break;

case ButtonPress:

rep_ptr = (struct XKeyEvent *)&report;

aear_traas(rep_ptr->x,rep_ptr->y,&id,&dist);

if (dist <= radius)

msgBuildSend(globTid, globTid, MSG_SELECT_TRANS.

ENCODE-BUTTON (report.xbuttou. button, id),

KS-NONE, MF_STANDARD);

near_place(rep_ptr->x,rep_ptr->y,&id,&dist);

if (dist <= radius)

msgBuildSend(globTid, globTid, MSG-SELECT-PLACE,

ENCODE-BUTTON (report.xbutton. button, id),

KS-NONE, MF_STANDARD);

break;

case KeyPress:

f = XLookupString(&report, buff, 5, &key, 0);

switch(key)

(case XK_t:

case XK_T:

msgBuildSend(globTid, globTid,

MSG-TOGGLE-TAGS,

NULL, MS-NONE, MF_STANDARD);

break;

case XK_s:

if (globTid != playTid)

(reclnfo(globTid,"Sending local mode: %d\n",

SINGLE-STEP);

ms Build(&msg, globTid, globTid, MSG-SET-MODE,

void *)SINGLE-STEP, MS-NONE, MF_STANDARD);

msgSend(&msg);

msgBuild(kmsg, playTid,globTid, MSG-SET-MODE,

(void *)SINGLE-STEP, MS_NONE, MF_STANDARD);

msgSend(&msg);

break;

case XK_S:

recInto(globTid,"Sending global mode: Y.d\n",

SINGLE-STEP);

msgBuild(Rmsg, globTid, globTid, MSG-SET_MODE,

(void *)SINGLE-STEP, MSNONE, MF_STANDARD);

msgSend(kmsg);

zsgBroadcast(&msg. MB_APPLICATION);

break;

case XK_c:

if (globTid != playTid)

(recInfo(globTid,"Sending local mode: %d\n",

CONTINUOUS);

msgBuild(&msg, globTid,globTid, MSG_SET_MODE,

(void *)CONTINUOUS, MS-NONE, MF_STANDARD);

msgSend(&msg);

msgBuild(&msg, playTid,globTid, MSG_SET_MODE,

". AMMAN.
13

(void • ) CONTINUOUS, MS-NONE. MF_STANDARD); 

msgSend ( kmsg);

break;

case XK_C:

recInfo(globTid. "Sending Global mode: YAW%

CONTINUOUS);

msgBuild ( &msg, globTid, globTid, MSG_SET_MODE,

(void • ) CONTINUOUS, MS NONE. MF_STANDARD);

msgSend( Amsg):

msgBroadcast(&msg, MB_APPLICATION);

break;

case XK_r:

case XK_R:

msgBuildSend (globTid. globTid,

MSG-DRAW-WHOLE-NET, NULL, 

MS NONE, MF_STANDARD);

break;

case XK_Left:

msgBuildSend(globTid, glob

MSG_SHIFT_DISPLAY,

(void *) LEFT, MS-NONE. MF_STANDARD);

shift _hor = LEFT;

rescale = TRUE;

break;

case XK_Right:

msgBuildSend (globTid, globTid,

MSG_SHIFT DISPLAY,

(void *) RIGHT, MSNONE, MF_STANDARD);

shift_hor = RIGHT;

rescale = TRUE;

break;

case XK_Up:

msgBuildSend(globTid, globTid,

MSG_SHIFT DISPLAY,

(void *)UP, MS-NONE, MF_STANDARD);

shift_ver = UP;

rescale = TRUE.-

break;

case XK_Dowu:

msgBuildSend(globTid, globTid,

MSG_SHIFT_DISPLAY,

(void *) DOWN, MS-NONE. MF_STANDARD);

shift_ver = DOWN;

rescale = TRUE; 

break; 

case XK_comma:

case XK_less: 

msgBuildSend (globTid, globTid,

MSG-CHANGE-SCALE, 

(void *) DEC, KS-NONE. MF_STANDARD);

size_chng = DEC;

rescale = TRUE;

break;

case IK_period:

case XK-neater: 
r

r 1

msgBuildSend (globTid. globTid,

MSG-CHANGE-SCALE,

(void *)INC. MS-NONE. MF_STANDARD);

size_chng = INC;

rascals = TRUE;

break;

case XK_q:

case XK_Q:

recPrompt ( globTid, but.

"Confirm Application Exit (y/n):

if ((buf [03 =_ ' y') I I (buf [03 =_ ' Y') )

msgipplicationExit (globTid)

break;

case XK_0:

case ILK-1:

case YK-2:

case XK_3:

case XK_4:

case XK_5:

case Xh_6:

case XK-7:

case XK_8:

case XX-9:

visible layer '= 1«(key-XK_0);

msgBvildSend (globTid, globTid, MSG_VISIBLE,

(void *)visible layer, MS-101E. MF_STABDARD)

break;

default:

break;

} /* end switch */

if (rascals)

{offset_x +_ (float ) HORI_SHIFT(shift_hoi);

offset_y +_ (float ) VER;_SHIFT ( shift ver);

scale +_ (float) ( size_chng*SCALE_FACTOR);

if (scale <= 0.0)

scale = 0.1;

rescale_net(scals, olfsat_x, offset-y);

shift_hor = shift_vez = size_chng = 0;

} /* end while */

}

D.? Xinter.c — User Selection of Places and Transitions

#include <stdio.h>

#include <math.h>

*include "Global_def.h"

extern struct Trans *trans;

extern struct Place *place;

extern int num_tr;

L
extern int n ua_pl;

/##+R###M*i#i#i###ii#####i##i##*##*#i###iiii####+M####i####ii##^R######i#ii#^K

* near-trans()

* This routine locates the transition nearest the point x,y. The

* variables id and dist are modified to reflect the id number

* of the transition and the distance to it in pixels.

near-trans(x.y.id .dist)

int x.y,*id,*dist;

{

int min. i;

min = (trans [O].x-loc-x )*(trans[0].x-loc-x) +

(trans[0] . y-loc-y) *(traas [0].y-loc-y);

*id = 0;

for (i=i;i<num-tr;i++)

{*dist = (trans[i].x-loc-x)*(trans [i].x-loc-x) +

(trans[i].y-loc-y)*(trans[i].y-loc-y);

if (*dist < min)

{min = *dist;

*id = i;

};

*dist = ( int)sgrt( (double) min);

}

* near-place()

* ?his routine locates the place nearest the point x,y. The

* variables id and dist are modified to reflect the id number

* of the place and the distance to it in pixels.

near-placc ( x,y,id,dist)

int x . y,*id,*dist;

{

int min, i;

min = (place[OI.x_loc-x )*(place [O].x-loc-x) +

(place [0].y-loc-y)*(place [0].y-lo4-y);

*id = 0;

for (i=l;i<num-pl;i++)

{*dist - (place[i].z loc-x)*(place [i].x-loc-x) +

(place[i].y-loc-y)*(place[i].y-loc-y);

if (*dist < min)

{min = *dist;

*id = i;

}

);

;

*disc = (int)sgrt( (double)min);

}

-- -. .—.- •.... .^.,^