Elevator Control System Modeling in SpecC

Elevator Control System Modeling in SpecC Andreas Gerstlauer Shuqing Zhao Technical Report ICS 98-XX June 1998 Department of Information and Comput...
Author: Godwin Banks
4 downloads 0 Views 119KB Size
Elevator Control System Modeling in SpecC

Andreas Gerstlauer Shuqing Zhao

Technical Report ICS 98-XX June 1998

Department of Information and Computer Science University of California, Irvine Irvine, CA 92692-3425, USA (714) 824-8059

[email protected] [email protected]

1

Introduction

Based on the two different understanding, we have two different implementation alternatives which will be described in detail later.

This technical report is a write up of a project for Professor Gupta’s ICS213 class - Embedded Software. The project is to model an elevator control system and construct a simulation. The modeling language we chose is SpecC [1,2,3,4]. In the following sections, we give the specification and briefly introduce the SpecC language. Then we describe the design and implementation of the elevator control system. Simulation and properties satisfied analysis are also included.

2

Specification

This elevator control system specification is taken from 4th International Workshop on Software Specification and Design, ACM SIGSOFT Software Engineering Notes, Vol. 11, No. 2, April 1986. The specification is as follows: 1. Within each lift (elevator) is a set of buttons, one on each floor. These illuminate when pressed and cause the lift to visit the corresponding floor. The illumination is canceled when the corresponding floor is visited by the lift. 2. Each floor has two buttons (except ground and top), one to request an up-lift and one to request a down-lift. These buttons illuminate when pressed. The buttons are canceled when a lift visits the floor and is either traveling in the desired direction, or visiting the floor with no requests (from the floor buttons stated in 1 above) outstanding. In the latter case if both floor requests are illuminated, only one should be canceled. The algorithm used to decide which to serve should minimize the waiting time for both requests. 3. When a lift has no requests to service, it should remain at its final destination with its doors closed and await further requests. 4. All requests for lifts from floors must be serviced eventually, with all floors given equal priority. 5. All requests for floors within lifts must be serviced eventually, with floors being serviced sequentially in the order of travel. 6. Each lift has an emergency button which, when pressed, causes a warning signal to be sent to the site manager. The lift is then deemed out-of-order. Each lift has a mechanism to cancel it out-of-order status. 7. A lift shall not make unrequested stops. 8. A request from a floor should not be the only cause for two lifts to stop at that floor at the same time. We are required to design a lift system that satisfy these requirements and construct a simulation. The lift system is a multi-elevator and multi-floor system. Clause 1,2 and 6 specify the configuration of the system like shown in Fig.1. Clause 8 above is not very clear to us. We have 2 different understandings. One is that a floor request could be the cause for two lifts to stop at that floor at the same time. The other is that a floor request should never be the cause for two lifts to stop at that floor at the same time.

12 34 56 78 E

Figure 1: Elevator configuration.

3

SpecC at a glance

SpecC is a C based hardware/software co-design language proposed by UCI CADLAB. It is a superset of ANSI-C with added features like communication channel, hierarchy, concurrency, timing abstraction, etc. It is designed to be a single language that can be used in all hardware/software codesign process stages, supporting homogeneous approach in contrast to existing heterogeneous approaches. A SpecC program consists of a set of behavior, channel and interface declarations. A behavior is a class consisting of a set of ports, such as p1 and p2 of behavior Z in Fig. 2; a set of sub-behaviors like x and y; a set of channels like c1 and c2 in behavior Z; a set of private variables and functions, and a public main func1

tion. Through its ports, a behavior can be connected to other behaviors or channels in order to communicate. The functionality of a behavior is specified by its function declarations. A channel is a class that encapsulates communication. It consists of a set of variables and functions, called methods, which define a communication protocol. A channel can be hierarchical, for example sub-channels can be used to specify lower level communication. An interface represents a flexible link between behaviors and channels. It consists of declarations of communication methods which will be defined in a channel. p1

The elevator subsystem consists of one elevator behavior and one elevator status and plan memory per elevator. The elevator behavior contains essentially the logic for controlling one elevator and its peripherals (e.g. buttons, etc.). Each elevator has an associated shared memory channel which is closely connected to the elevator behavior and holds both, the current elevator status (current floor, direction) and the elevator plan with all outstanding requests the elevator has to service. The floor subsystem handles and dispatches incoming request from the floor buttons. The current floor status, i.e. the status of requests at each floor is stored in an associated floor status shared memory channel. Finally, the system includes a centralized scheduler behavior which is responsible for assigning floor requests to elevators. The necessity for some sort of scheduling strategy arises because of the fact that in a multiple-elevator system one and possibly only one elevator should be committed to service a certain floor requests. Consider, for example, a case where all elevators are standing and waiting for requests. If then a floor request comes in one and only one elevator should start moving to pick up that request. In our design we decided to implement a basically centralized scheduling strategy although in a real-life implementation this might have negative consequences in terms of fault tolerance (which could be solved by duplicating the scheduler, for example). Alternatively, one could think of using a distributed scheduling algorithm. This would require that the elevators communicate with each other using some sort of protocol to determine which elevator commits to service an incoming floor request. However, due to the distributed nature such an algorithm can get rather complicated quickly and it is considerably harder to prove certain properties, e.g. about fairness, etc. in comparison to a centralized algorithm. The centralized scheduler in the elevator control system receives floor request messages from the floor subsystem. It reads the status and plans of all elevators in the system and finally assigns the floor request to one of the elevators by putting the request in the corresponding elevator’s plan. For our system we have actually implemented two different alternative designs relating to the scheduling strategy. The first version is based on a purely centralized scheduling concept in which the elevators only stop at floors for which they have any outstanding requests (either from internal buttons or assigned by the scheduler). In the second alternative the elevators actually participate actively in the scheduling decisions resulting in a somehow mixed centralized/distributed scheduling concept. In this case the elevators have access to the floor status memory (as shown by the dashed connections in Figure 3) and they check at every floor they pass while moving whether there are any requests on that floor they are able to service on their move. If there is a request the elevator stops and picks up the request even when it hasn’t been assigned to this elevator.

p2

Z

c2 c1

X

p3

p2

p1

Y

p1

p2

p3

(a) interface ILeft { void write( int val ); }; interface IRight { int read( void ); }; channel CSharedl( void ) implements ILeft, IRight { int storage; bool valid; void

int

write( int val ) { storage = val; valid = true; } read( void ) { while( !valid ); return storage; }

behavior X( in int p1, ILeft p2, in int p3 ) { int local; void

main( void ) { .... p2.write( local ); ... }

}; behavior Z( in int p1, out int p2 ) { int c1; CShared c2; X Y

x( c1, c2, p1 ); y( c1, c2, p2 );

void main( void ) { par { x.main(); y.main(); } } };

}; behavior Y( out int p1, IRight p2, out int p3 ) { int local; void

main( void ) { ... local = p2.read(); ... }

};

(b)

Figure 2: Basic Structure of a SpecC program.

4

Design and Implementation

4.1 General 4.1.1

Architecture

The top-level architecture of the elevator control system implementation is shown in Figure 3. Basically, the system is divided into three major parts: the elevator subsystem, the floor subsystem and the centralized scheduler. 2

Elevator Button Requests

Request/Cancel Floor

Floor Request Buttons (up / down)

Floor

Elevator

Status and Plan Floor Status

Elevator Button Requests

Status and Plan

Scheduler

Elevator

Floor arrivals

Figure 3: Top-level architecture 4.1.2

4.2 Floor Subsystem

Event Flows

There are three general event flows through the system: incoming elevator button request events, incoming floor request events and events signalling arrivals of elevators at floors. Incoming elevator button requests are handled by the corresponding elevator subsystem which just puts the request in the elevator’s plan memory. Incoming floor requests are handled by the floor subsystem. The floor subsystems receives the request event and updates the floor status memory accordingly. In addition, the floor subsystem puts a request message into the scheduler input FIFO queue. The scheduler then decides which elevator should service the request and puts the request in the elevator’s plan memory.

Scheduler Queue

As the elevators move through the system they will eventually stop at certain floors. Upon arrival at a floor the elevator sends an event to the floor system signalling that the elevator visits the floor going in a certain direction. In the floor system this results in clearing any corresponding request at that floor, removing the entry from the floor status memory. The floor subsystem also puts a cancel message into the scheduler input queue upon which the scheduler removes this floor request from all the elevators in the system. Note that an elevator might actually service a floor request even though the request hasn’t been assigned to the elevator in cases where the elevator stops at the floor due to an internal button request. Therefore, killing the requests in all elevator plans ensures that assigned elevator doesn’t have to service the request any more.

Floor Status

Set Floor Requests

Clear Floor Requests

Floor Request Buttons

Floor Arrivals

Figure 4: Floor subsystem architecture. Figure 4 shows the composition of the floor subsystem behavior. It is composed of two simple subbehaviors running in parallel, one for handling incoming floor requests and one for handling floor arrival events. Each of the two behaviors just listens to the corresponding events, updating the floor status memory and putting messages into the scheduler queue accordingly. The associated floor status memory is just an array with two elements per floor to store the status of the up/down requests at each floor.

3

4.3 Elevator Subsystem 4.3.1

Idle

General

As mentioned previously, the elevator subsystem consists of one elevator behavior and one elevator memory per elevator. Each elevator memory in turn is divided into an elevator status and an elevator plan. The elevator status comprises the current floor, the current direction (up, down or none) and the out-of-order status of the elevator. The elevator plan is an array which stores the outstanding elevator requests for each floor. At each floor the plan can contain any combination of floor up, floor down and button requests which the elevator will have to service. Elevator Status and Plan

Elevator Control State Machine

Elevator Button Requests

Floor Arrivals

Open Doors clear requests

stop at

Move to next floor

current floor

keep moving

move one floor, check for stop

Figure 6: Elevator controller state machine. floor the elevator is currently at the machine transitions to the open doors state. This could either be because somebody inside the elevator pressed the button for the current floor or because the scheduler assigned a request from the current floor to us after a user pressed the request button outside. For floor requests the transitions also has to be conditioned on the current moving direction and on the direction of the request. On the other hand, if the elevator has currently no predefined direction a request at the current floor assigns one. Upon entering the open doors state the door movement is initiated and the floor and button requests corresponding to the current floor and the current moving direction are cleared by removing any button request from the plan and by notifying the floor arrival event for the floor subsystem (which will in turn clear the corresponding floor request in the elevator plan, too). The controller stays in the open doors state as long as passengers enter the cabin and the timeout is not expired. Eventually, the controller will then transition back to closing the doors. Finally, if there is no request for the current floor but the plan contains an outstanding request for any other floor the elevator transitions to the moving state. If necessary, the elevator moving direction is checked and set on this transition. In the moving state the elevator travels from floor to floor. Upon arrival at the next floor the controller checks whether the elevator should stop at that floor, i.e. if there are any button requests or floor requests in our direction to service. If no stop is required the elevator just keeps moving. Eventually, the elevator will stop and transition to the open doors state. On this transition the elevator plan is checked to preset the direction (if any) for the movement after the stop (which in turn will determine which floor request is serviced at this floor).

Figure 5: Elevator subsystem architecture. Figure 5 shows the elevator behavior composition. Similar to the floor behavior, it contains one simple subbehavior which handles the elevator button requests by just putting them into the elevator plan. In parallel to that runs the actual elevator state machine which controls the movement of the elevator depending on the elevator plan and which issues floor arrival events upon stopping at a certain floor. In our second implementation alternative the elevator controller state machine also accesses the shared floor status memory. 4.3.2

request for other floor

request for current floor

Floor Status

Request Handler

Closed Doors

Elevator State Machine.

The elevator controller state machine is shown in Figure 6. In order to keep our implementation simple the state machine just consists of three basic, top-level states: doors closed, doors open and cabin moving. In a real-life implementation these states would have to be further decomposed hierarchically in order to provide additional control for the peripherals like door and cabin motors. For example, the toplevel moving state would have to start the elevator motor, wait for the next floor arrival sensor and eventually stop the motor, possibly gradually decreasing speed, etc. Initially, the elevators start of with the doors closed. The controller stays in that state as long as there are no requests to service in the elevator plan. If there is a request for the

4.4 Out of Order Handling So far, the architecture description shown in the previous sections didn’t include handling of out of order situations. The out of order process actually requires some changes to the overall design which will be described in the following paragraphs. 4

First of all, if the cabin is currently moving when the emergency button is pressed the elevator immediately stops at the next floor and opens the doors to let the passengers out. This requires that the out of order status is included when checking for stops in the elevator controller moving state. After reaching the closed doors state the controller will then in any case stay in that state until the out of order status is released. The only exception is when somebody inside the elevator presses the button for the current floor in which case the controller opens the doors to let the passenger out. Emergency button requests are received by the button handler in the elevator behavior. Emergency button events toggle the out of order status in the elevator memory. Upon entering the out of order status the button handler clears all button requests in the elevator plan. Further button request events are then ignored until the out of order status is left. On the other hand, the scheduler checks the elevator status before assigning floor requests and simply ignores elevators that are out of order such that no new request will be assigned to unavailable elevators. In addition, it has to be ensured that all the floor requests that have already been assigned to the out of order elevator will be serviced eventually by some other available elevator. This has been implemented by adding a connection from the elevator button handler to the scheduler input queue. As soon as an elevator goes out of order its button handler will reschedule the assigned floor requests by putting them into the scheduler input queue.

formula to represent the dynamically changing unpredictable closeness measure. Dist = Number of floors passed + Number of stops Here we treat one stop as one floor distance although in real life it might take longer or shorter than one stop depending on the speed of the elevator. We use only the example of a floor up-request to explain how we compute the distance. For floor down-request it is very easy to derive the solution. If the elevator is in idle state, the distance is easy to compute. It is just the number of floors between the floor request and the elevator. If the elevator is moving upwards, like shown in Figure 7 there are three cases. First, the elevator is below the floor request. The distance is equal to the sum of the number of floors and stops in between. Second, if the elevator is above the floor request and the lower bound of the downwards request within the elevator is above the floor request, the distance is the sum of the length of the middle gray path and stops in between. The top of the gray path is the upper bound of the requests within the elevator. Third, if the elevator is above the floor request and the lower bound of the downwards request within the elevator is below the floor request, the distance is the sum of the length of the right gray path and stops in between.

4.5 Scheduler The scheduler takes the floor request from the queue, find the appropriate elevator to service this request and send the request to the corresponding elevator. Our algorithm base on the goal to minimize the waiting time of the floor request without considering the possible delay it may introduce to the service of the original requests within the elevator. The idea of the algorithm is to find the most “close” elevator to service the floor request. The pseudo code of the algorithm is as follows: Begin minDist = ∞ ; minElv = -1; for i ∈ E :all elevators available{ compute the distance -dist- between the elevator and the floor request; if (dist “, t); if (!gets(buf)) return; fputs(buf, log); fprintf(log, “\n”); switch (buf[0]) { case ‘r’: if (sscanf(buf, “r %d”, ¶m) == 1) { waitfor(param); } break; case ‘t’: t = now(); printf (“Time: %lld\n”, t); break;

13

case ‘1’: if (sscanf(buf, “1 %d”, ¶m) == 1) { switch (param) { case 1: notify (el1fl1); break; case 2: notify (el1fl2); break; case 3: notify (el1fl3); break; case 4: notify (el1fl4); break; case 5: notify (el1fl5); break; case 6: notify (el1fl6); break; case 7: notify (el1fl7); break; case 8: notify (el1fl8); break; case 9: notify (el1fl9); break; case 10: notify (el1fl10); break; default: printf (“Invalid floor number\n”); } } else if (buf[2] == ‘e’) { notify (el1outOfOrder); } else { printf (“Invalid parameter (neither floor number nor ‘e’)\n”); } break; case ‘2’: if (sscanf(buf, “2 %d”, ¶m) == 1) { switch (param) { case 1: notify (el2fl1); break; case 2: notify (el2fl2); break; case 3: notify (el2fl3); break; case 4: notify (el2fl4); break; case 5: notify (el2fl5); break; case 6: notify (el2fl6); break; case 7: notify (el2fl7); break; case 8: notify (el2fl8); break; case 9: notify (el2fl9); break; case 10: notify (el2fl10); break; default: printf (“Invalid floor number\n”); } } else if (buf[2] == ‘e’) { notify (el2outOfOrder); } else { printf (“Invalid parameter (neither floor number nor ‘e’)\n”); } break; case ‘3’: if (sscanf(buf, “3 %d”, ¶m) == 1) { switch (param) { case 1: notify (el3fl1); break; case 2: notify (el3fl2); break; case 3: notify (el3fl3); break; case 4: notify (el3fl4); break; case 5: notify (el3fl5); break; case 6: notify (el3fl6); break; case 7: notify (el3fl7); break; case 8: notify (el3fl8); break; case 9: notify (el3fl9); break; case 10: notify (el3fl10); break; default: printf (“Invalid floor number\n”); } } else if (buf[2] == ‘e’) {

14

notify (el3outOfOrder); } else { printf (“Invalid parameter (neither floor number nor ‘e’)\n”); } break; case ‘u’: if (sscanf(buf, “u %d”, ¶m) == 1) { switch (param) { case 1: notify (fl1up); break; case 2: notify (fl2up); break; case 3: notify (fl3up); break; case 4: notify (fl4up); break; case 5: notify (fl5up); break; case 6: notify (fl6up); break; case 7: notify (fl7up); break; case 8: notify (fl8up); break; case 9: notify (fl9up); break; default: printf(“Invalid floor number\n”); } } break; case ‘d’: if (sscanf(buf, “d %d”, ¶m) == 1) { switch (param) { case 10: notify (fl10down); break; case 2: notify (fl2down); break; case 3: notify (fl3down); break; case 4: notify (fl4down); break; case 5: notify (fl5down); break; case 6: notify (fl6down); break; case 7: notify (fl7down); break; case 8: notify (fl8down); break; case 9: notify (fl9down); break; default: printf(“Invalid floor number\n”); } } break; case ‘q’: fclose (log); system(“killall tail -f elevator 1> /dev/null 2>&1 &”); notify (quit); return; default: printf(“\nCommands:\n\n”); printf(“ r printf(“ 1/2/3 printf(“ printf(“ u printf(“ d printf(“ q } } } };

Run simulation for certain time.\n\n”); Elevator floor request buttons\n”); for elevator 1, 2 or 3.\n\n”); Up request at given floor.\n\n”); Down request at given floor.\n\n”); Quit.\n\n”);

// --- Elevator control system

15

// Cleanup at end of simulation behavior Cleanup (void) { void main(void) { } };

// Unit under test behavior UUT( in event quit, in event el1fl1, in event el2fl1, in event el3fl1, in event el1fl2, in event el2fl2, in event el3fl2, in event el1fl3, in event el2fl3, in event el3fl3, in event el1fl4, in event el2fl4, in event el3fl4, in event el1fl5, in event el2fl5, in event el3fl5, in event el1fl6, in event el2fl6, in event el3fl6, in event el1fl7, in event el2fl7, in event el3fl7, in event el1fl8, in event el2fl8, in event el3fl8, in event el1fl9, in event el2fl9, in event el3fl9, in event el1fl10, in event el2fl10, in event el3fl10, in event el1outOfOrder, in event el2outOfOrder, in event el3outOfOrder, in event fl1up, in event fl2up, in event fl2down, in event fl3up, in event fl3down, in event fl4up, in event fl4down, in event fl5up, in event fl5down, in event fl6up, in event fl6down, in event fl7up, in event fl7down, in event fl8up, in event fl8down, in event fl9up, in event fl9down, in event fl10down) { ElevatorSystem system(el1fl1, el2fl1, el3fl1, el1fl2, el2fl2, el3fl2, el1fl3, el2fl3, el3fl3, el1fl4, el2fl4, el3fl4, el1fl5, el2fl5, el3fl5, el1fl6, el2fl6, el3fl6, el1fl7, el2fl7, el3fl7, el1fl8, el2fl8, el3fl8, el1fl9, el2fl9, el3fl9, el1fl10, el2fl10, el3fl10, el1outOfOrder, el2outOfOrder, el3outOfOrder, fl1up, fl2up, fl2down, fl3up, fl3down, fl4up, fl4down, fl5up, fl5down, fl6up, fl6down, fl7up, fl7down, fl8up, fl8down, fl9up, fl9down, fl10down); Cleanup cleanup; void main (void) { try { system.main(); } trap (quit) { cleanup.main(); } } };

16

// --- Testbench behavior Main { event quit; event event event event event event event event event event event

el1fl1; event el2fl1; event el3fl1; el1fl2; event el2fl2; event el3fl2; el1fl3; event el2fl3; event el3fl3; el1fl4; event el2fl4; event el3fl4; el1fl5; event el2fl5; event el3fl5; el1fl6; event el2fl6; event el3fl6; el1fl7; event el2fl7; event el3fl7; el1fl8; event el2fl8; event el3fl8; el1fl9; event el2fl9; event el3fl9; el1fl10; event el2fl10; event el3fl10; el1outOfOrder; event el2outOfOrder; event el3outOfOrder;

event event event event event event event event event event

fl1up; fl2up; event fl3up; event fl4up; event fl5up; event fl6up; event fl7up; event fl8up; event fl9up; event fl10down;

fl2down; fl3down; fl4down; fl5down; fl6down; fl7down; fl8down; fl9down;

UUT uut(quit, el1fl1, el2fl1, el3fl1, el1fl2, el2fl2, el3fl2, el1fl3, el2fl3, el3fl3, el1fl4, el2fl4, el3fl4, el1fl5, el2fl5, el3fl5, el1fl6, el2fl6, el3fl6, el1fl7, el2fl7, el3fl7, el1fl8, el2fl8, el3fl8, el1fl9, el2fl9, el3fl9, el1fl10, el2fl10, el3fl10, el1outOfOrder, el2outOfOrder, el3outOfOrder, fl1up, fl2up, fl2down, fl3up, fl3down, fl4up, fl4down, fl5up, fl5down, fl6up, fl6down, fl7up, fl7down, fl8up, fl8down, fl9up, fl9down, fl10down); Generator generator(quit, el1fl1, el2fl1, el3fl1, el1fl2, el2fl2, el3fl2, el1fl3, el2fl3, el3fl3, el1fl4, el2fl4, el3fl4, el1fl5, el2fl5, el3fl5, el1fl6, el2fl6, el3fl6, el1fl7, el2fl7, el3fl7, el1fl8, el2fl8, el3fl8, el1fl9, el2fl9, el3fl9, el1fl10, el2fl10, el3fl10, el1outOfOrder, el2outOfOrder, el3outOfOrder, fl1up, fl2up, fl2down, fl3up, fl3down,

17

fl4up, fl4down, fl5up, fl5down, fl6up, fl6down, fl7up, fl7down, fl8up, fl8down, fl9up, fl9down, fl10down); void main(void) { par { uut.main(); generator.main(); } } };

• filename: elevator.sc // // // // //

-----------------------------------------------------------------------elevator.sc - Controller for single elevator -----------------------------------------------------------------------06/09/98

A.Gerstlauer

#include “global.sh” #include //#include

import “lampd”; import “fifo”;

// Entries in elevator plan #define NOSTOP 0 #define FLOOR_REQUEST_UP 1 #define FLOOR_REQUEST_DN 2 #define ELEVATOR_REQUEST 4

// -----------------------------------------------// Interface for externals to connect with elevator interface IElevator { // Schedule/clear floor requests for the elevator void setRequest (int floor, bool up); void clearRequest(int floor, bool up); // Get current status int getCurFloor (void); bit[1:0] getCurDir (void); // Get the number of stop we will make on a run int elvReqStops (int* min, int* max); int floorReqStops (int from, int to); };

// -----------------------------------------------// Shared elevator memory (plan/status)

18

channel CElevator (int num) implements IElevator { int plan[FLOORS]; // scheduled stops int at; bit[1:0] dir;

// Elevator is at floor i, going up/down or nowhere

event waitEv; bool waiting;

// waiting for requests...

bool

outOfOrder;

// Debugging output FILE* f; void dump(void) { int i; long long t; t = now(); fprintf(f, “%10lld: “, t); if (outOfOrder) { fprintf (f, “ “); } else { switch(dir) { case DIR_UP: fprintf(f, “(U) “); break; case DIR_DOWN: fprintf(f, “(D) “); break; default: fprintf(f, “ “); } fprintf(f, “(%d) “, at+1); } fprintf(f, “\t[ “); for (i = 0; i < FLOORS; i++) { if (plan[i] & ELEVATOR_REQUEST) fprintf(f, “(%d) “, i+1); else fprintf(f, “ %d “, i+1); } fprintf(f, “]\n”); } // Init memory void init(void) { char buf[32]; int i; for (i = 0; i < FLOORS; i++) plan[i] = 0; at = 0; dir = DIR_NONE; waiting = false; outOfOrder = false; sprintf(buf, “elevator%d.out”, num); f = fopen(buf, “w”); setbuf(f, 0); dump(); }

// --- External interface to scheduler void setRequest(int floor, bool up)

19

{ plan[--floor] |= (up? FLOOR_REQUEST_UP : FLOOR_REQUEST_DN); if (waiting) { if (floor < at) dir = DIR_DOWN; else dir = (floor > at); } if ((!dir) && (at == floor)) { dir = (up? DIR_UP : DIR_DOWN); } dump(); waiting = false; notify (waitEv); } void clearRequest(int floor, bool up) { plan[--floor] &= ~(up? FLOOR_REQUEST_UP : FLOOR_REQUEST_DN); } int getCurFloor (void) { if (outOfOrder) return 0; else return at+1; } bit[1:0] getCurDir (void) { return dir; } int elvReqStops (int* min, int* max) { int i; int oldmin, oldmax; int stops; // Save values oldmax = *max; oldmin = *min; // Initialize for setting bounds *max = oldmin; *min = oldmax; // Count stops stops = 0; for (i = oldmin; i < oldmax - 1; i++) { if (plan[i] & ELEVATOR_REQUEST) stops++; // Set bounds of available requests if (plan[i]) { if ((i+1) > *max) *max = i+1; if ((i+1) < *min) *min = i+1; } } return stops; } int floorReqStops (int from, int to) { int i, d, f; int stops; // Figure out direction if (--from > --to) { d = -1; f = FLOOR_REQUEST_DN; } else { d = 1 ; f = FLOOR_REQUEST_UP; } // Loop over it, count stops stops = 0; for (i = from; i != to; i += d) { if (plan[i] & f) stops++; } return stops;

20

}

// --- Interface to elevator control void setButton(int floor) { // In case of “out of order” only allow requests for current floor if (outOfOrder && (floor != at)) return; // Set request plan[floor] |= ELEVATOR_REQUEST; // Set direction if we were idle if (!dir) { if (floor < at) dir = DIR_DOWN; else dir = (floor > at); } dump(); // Wake up, if necessary waiting = false; notify (waitEv); } void clearButton (void) { plan[at] &= ~ELEVATOR_REQUEST; } void outOfOrderButton (Iinfifo scheduler) { int i; // Toggle out of order outOfOrder = !outOfOrder; // Go into “out of order” status? if (outOfOrder) { // Clear all requests, we are out of business for (i = 0; i < FLOORS; i++) { // Reschedule any floor requests if (plan[i] & FLOOR_REQUEST_UP) scheduler.put(i+1, UP); if (plan[i] & FLOOR_REQUEST_DN) scheduler.put(i+1, DOWN); plan[i] = 0; } } if (waiting) dump(); } int nextFloor (void) { int i; i = at; do { i += dir; if (i < 0) i = FLOORS - 1; else i %= FLOORS; } while ((i != at) && (!plan[i])); return i; } bool checkFloor(bool upReq, bool dnReq) { bool up, dn; int i; #ifndef ELEVATOR_CHECK_FLOOR // Don’t check floor requests not assigned to us

21

upReq = false; dnReq = false; #endif // Look for requests in plan i = nextFloor(); // What floor requests can be satisfied? up = (upReq || (plan[at] & FLOOR_REQUEST_UP)) && ((i >= at) || (dir > 0)); dn = (dnReq || (plan[at] & FLOOR_REQUEST_DN)) && ((i at) dir = DIR_DOWN; else dir = DIR_UP; } return true; } // Single requests? if (up) { dir = DIR_UP; return true; } if (dn) { dir = DIR_DOWN; return true; } // Preset direction if (i < at) dir = DIR_DOWN; else dir = (i > at); // Button in elevator requested? if (plan[at] & ELEVATOR_REQUEST) return true; return false; }

int getNextRequest(void) { // If no directions, give default if (!dir) { if (at < (FLOORS/2)) dir = DIR_DOWN; else dir = (at > (FLOORS/2)); } if (!dir) dir = DIR_DOWN; // Check for requests on current floor, set direction to go if (checkFloor(false, false)) return DIR_NONE; // No stop, no directions -> wait if (!dir) { waiting = true; wait (waitEv); // Any requests at current floor to satisfy? if ((plan[at] & FLOOR_REQUEST_UP) && (dir > 0)) return DIR_NONE; if ((plan[at] & FLOOR_REQUEST_DN) && (dir < 0)) return DIR_NONE; } return dir; } };

// -----------------------------------------------// Elevator control state machine

22

// --- Closing doors state behavior CloseDoors (CElevator plan) { void main (void) { long long t; t = now(); fprintf(plan.f, “%10lld: Close door\n”, t); } };

// --- Moving cabin state behavior Move(CElevator plan, Iinlamp floors) { int dest; // Check upon arrival at a floor if we should stop bool stop(void) { int olddir; olddir = plan.dir; // Check if there are any requests for this floor if (plan.checkFloor(floors.get(plan.at, true), floors.get(plan.at, false))) return true; // No request but we are suggested to change direction if (olddir != plan.dir) { // At original destination? if (dest == plan.at) return true; // Out of order? if (plan.outOfOrder) return true; // No: keep moving, don’t stop plan.dir = olddir; } else { // No request, keep moving in same direction -> get new destiny dest = plan.nextFloor(); } return false; } void main (void) { // Where are we supposed to go now? dest = plan.nextFloor(); // Move do { plan.at += plan.dir; plan.dump(); waitfor (MOVE_CABIN_DELAY); } while (!stop()); } };

// --- Arrival at floor, opening doors state behavior OpenDoors (CElevator plan, out event atfloor10dn, out event atfloor9up, out event atfloor9dn, out event atfloor8up, out event atfloor8dn,

23

out out out out out out out

event event event event event event event

atfloor7up, atfloor6up, atfloor5up, atfloor4up, atfloor3up, atfloor2up, atfloor1up)

out out out out out out

event event event event event event

atfloor7dn, atfloor6dn, atfloor5dn, atfloor4dn, atfloor3dn, atfloor2dn,

{ void atFloor(void) { switch(plan.at) { case 0: if (plan.dir > 0) notify(atfloor1up); break; case 1: if (plan.dir > 0) notify(atfloor2up); if (plan.dir < 0) notify(atfloor2dn); break; case 2: if (plan.dir > 0) notify(atfloor3up); if (plan.dir < 0) notify(atfloor3dn); break; case 3: if (plan.dir > 0) notify(atfloor4up); if (plan.dir < 0) notify(atfloor4dn); break; case 4: if (plan.dir > 0) notify(atfloor5up); if (plan.dir < 0) notify(atfloor5dn); break; case 5: if (plan.dir > 0) notify(atfloor6up); if (plan.dir < 0) notify(atfloor6dn); break; case 6: if (plan.dir > 0) notify(atfloor7up); if (plan.dir < 0) notify(atfloor7dn); break; case 7: if (plan.dir > 0) notify(atfloor8up); if (plan.dir < 0) notify(atfloor8dn); break; case 8: if (plan.dir > 0) notify(atfloor9up); if (plan.dir < 0) notify(atfloor9dn); break; case 9: if (plan.dir < 0) notify(atfloor10dn); } } void main (void) { long long t; plan.clearButton(); plan.dump(); atFloor(); t = now(); fprintf(plan.f, “%10lld: Open door\n”, t); waitfor(OPEN_DOORS_DELAY); } };

// -- FSM behavior ElevatorControl (CElevator plan, Iinlamp floors, out event atfloor10dn, out event atfloor9up, out event atfloor9dn, out event atfloor8up, out event atfloor8dn, out event atfloor7up, out event atfloor7dn, out event atfloor6up, out event atfloor6dn, out event atfloor5up, out event atfloor5dn, out event atfloor4up, out event atfloor4dn,

24

out event atfloor3up, out event atfloor3dn, out event atfloor2up, out event atfloor2dn, out event atfloor1up) { CloseDoors closeDoors (plan); Move moveCab (plan, floors); OpenDoors openDoors (plan, atfloor10dn, atfloor9up, atfloor9dn, atfloor8up, atfloor8dn, atfloor7up, atfloor7dn, atfloor6up, atfloor6dn, atfloor5up, atfloor5dn, atfloor4up, atfloor4dn, atfloor3up, atfloor3dn, atfloor2up, atfloor2dn, atfloor1up); void main(void) { plan.init(); fsm { closeDoors: if (!plan.getNextRequest()) goto openDoors; moveCab

: { }

openDoors : goto closeDoors; } } };

// -----------------------------------------------// Single Elevator

// --- Handler for elevator button events behavior HandleButton (int button, in event buttonPressed, CElevator plan, Iinfifo scheduler) { void main (void) { int i; while (1) { // Wait for button wait (buttonPressed); // Out of order button? if (button < 0) { plan.outOfOrderButton(scheduler); } else { plan.setButton (button); } } } };

// --- Elevator behavior behavior Elevator (CElevator plan, Iinlamp floors, Iinfifo scheduler, out event atfloor10dn, out event atfloor9up, out event atfloor9dn,

25

out event atfloor8up, out event out event atfloor7up, out event out event atfloor6up, out event out event atfloor5up, out event out event atfloor4up, out event out event atfloor3up, out event out event atfloor2up, out event out event atfloor1up, in event button1, in event button2, in event button3, in event button4, in event button5, in event button6, in event button7, in event button8, in event button9, in event button10, in event buttonOutOfOrder)

atfloor8dn, atfloor7dn, atfloor6dn, atfloor5dn, atfloor4dn, atfloor3dn, atfloor2dn,

{ ElevatorControl elevatorControl(plan, floors, atfloor10dn, atfloor9up, atfloor9dn, atfloor8up, atfloor8dn, atfloor7up, atfloor7dn, atfloor6up, atfloor6dn, atfloor5up, atfloor5dn, atfloor4up, atfloor4dn, atfloor3up, atfloor3dn, atfloor2up, atfloor2dn, atfloor1up); int b0 = 0; HandleButton handleButton1(b0, button1, plan, scheduler); int b1 = 1; HandleButton handleButton2(b1, button2, plan, scheduler); int b2 = 2; HandleButton handleButton3(b2, button3, plan, scheduler); int b3 = 3; HandleButton handleButton4(b3, button4, plan, scheduler); int b4 = 4; HandleButton handleButton5(b4, button5, plan, scheduler); int b5 = 5; HandleButton handleButton6(b5, button6, plan, scheduler); int b6 = 6; HandleButton handleButton7(b6, button7, plan, scheduler); int b7 = 7; HandleButton handleButton8(b7, button8, plan, scheduler); int b8 = 8; HandleButton handleButton9(b8, button9, plan, scheduler); int b9 = 9; HandleButton handleButton10(b9, button10, plan, scheduler); int bO = -1; HandleButton handleButtonO(bO, buttonOutOfOrder, plan, scheduler); void main (void)

26

{ par { elevatorControl.main(); handleButton1.main(); handleButton2.main(); handleButton3.main(); handleButton4.main(); handleButton5.main(); handleButton6.main(); handleButton7.main(); handleButton8.main(); handleButton9.main(); handleButton10.main(); handleButtonO.main(); } } };

• filename: scheduler.sc // // // // //

-----------------------------------------------------------------------scheduler.sc - Central scheduler for floor button requests -----------------------------------------------------------------------06/09/98

S.Zhao

#define Z 3 #include “global.sh” #include

import “fifo”; import “elevator”;

// FIFO input queue // Elevators

behavior Scheduler(Ioutfifo i1, IElevator i2, IElevator i3, IElevator i4) { void main(void) { long long t; flreq curreq; bit[1:0] elvDir; int curFloor; int minElv, minDist; int i, stops, dist, elrqstops, flrqstops; int lbound, ubound; while(1) { curreq = i1.get(); minDist=40; minElv=-1; for(i=1; i= curreq.flno) { ubound = curFloor; lbound = curreq.flno; stops = i2.elvReqStops(&lbound, &ubound) + i2.floorReqStops(curFloor, curreq.flno); dist = - (curreq.flno - curFloor) + stops; } else { lbound = 0; ubound = 11; elrqstops = i2.elvReqStops(&lbound, &ubound); if (ubound = curreq.flno) { ubound = curFloor; lbound = curreq.flno; stops = i3.elvReqStops(&lbound, &ubound) + i3.floorReqStops(curFloor, curreq.flno); dist = - (curreq.flno - curFloor) + stops; } else { lbound = 0; ubound = 11; elrqstops = i3.elvReqStops(&lbound, &ubound); if (ubound = curreq.flno) { ubound = curFloor; lbound = curreq.flno; stops = i4.elvReqStops(&lbound, &ubound) + i4.floorReqStops(curFloor, curreq.flno); dist = - (curreq.flno - curFloor) + stops; } else { lbound = 0; ubound = 11; elrqstops = i4.elvReqStops(&lbound, &ubound); if (ubound

Suggest Documents