Monday, September 7, 2009

Fun with Debugging: The Elevator

After some amusing, confusing and somewhat annoying experiences with a very old elevator in the appartment house I'm living in, I've decided to let you join the fun. It took me some time to figure out how that elevator was probably programmed, but I think I by now have a pretty accurate model of how it works. I think it's an excellent example of well-intended programming going horribly wrong and would not want to deprive anyone out there from the chance to learn from it. (Nothing is worthless -- it can still be a bad example.)

Below you will find the details on how the elevator is programmed. Your task: Find as many use cases as possible where the elevator will not do what the user(s) would have expected.

=======================================
Let's assume some parts are implemented in hardware and all parts will work in parallel. The elevator has exactly one variable: destination, denoting the floor the elevator should go to. It furthermore can determine its current position, using a function named getPosition().

Whenever getPosition() != destination, i.e. the elevator is not where it should go to, the engine will move the elevator cabin towards the destination.

The doors are controlled mechanically. They can not be opened automatically (like modern elevator doors), but have to be pushed (or pulled) open manually by the persons using the elevator. The doors can however be locked or unlocked, which will happen semiautomatically. The function lockDoors() will lock all the doors. The function unlockDoors() will unlock the door where the cabin currently is. (That is, if the elevator is in floor 4, the door of floor 4 will be unlocked. If the elevator is not in front of any door, for example after someone pressing the emergency stop, no doors will be unlocked.) Additionally, it is possible to find out if a door is open, using a function isDoorOpen() that will return true if and only if at least one door is open. (Here, "open" means that the door is not only unlocked but also is currently opened.)

All movements of the cabin are therefore solely dependent on destination. An event-based structure will control this variable. There are four possible events:
* onButtonInCabinPressed(floor) will be invoked when a floor button in the cabin has been pressed, where floor denotes the number that was pressed.
* onCallButtonPressed(floor) will be invoked when the button outside the elevator has been pressed to call the elevator. Here, floor denotes the floor where the button was pressed.
* onStopButtonPressed() will be invoked when the emergency stop button in the elevator cabin is pressed.
* onDestinationReached() will be invoked when the cabin reaches its destination, i.e. when the cabin used to be moving because getPosition() != destination, and is not moving any more because the current position now equals the destination.

The first three functions will be called repeatedly as long as the buttons are being pressed. If more than one button is pressed at a time, the stop button will precede the other buttons, and the buttons inside the cabin will precede the call buttons outside.

For the simplicity of the code, let's assume that assert(...) will abort the execution of the called function if the assertion doesn't hold, but will not otherwise influence the state of the elevator.

Further, let's assume all of the following functions are atomical, that is, they will be executed to the end before another function can be executed. Also, the execution of one function will happen so fast that no human can change anything about the state in the meantime, i.e. the result of isDoorOpen() can't change during the execution of one function.

Here is the code for four abovementioned functions and their helper functions:

// Button in cabin has been pressed
onButtonInCabinPressed(floor) {
setDestination(floor);
}

// Call button has been pressed
onCallButtonPressed(floor) {
setDestination(floor);
}

// This function sets the new destination if possible. As both calling
// the elevator and pressing a floor button boil down to setting a new
// destination, we can use the same code for both.
setDestination(newdestination) {
// If the elevator is already moving and we set a new destination,
// it might start moving in the other direction instead of taking
// the people inside the cabin to the floor they wanted to go to.
// For example, if the elevator was moving up from the 2nd floor
// to the 5th, and someone in the 1st floor called the elevator,
// without this check it would turn around and go to the 1st floor.
// We therefore must assure the cabin is currently standing.
assert(getPosition() == destination);

// As soon as we set a new destination, the elevator will start
// moving. If the door is still open at that moment, it will both
// damage the mechanical locking system and endager the people
// currently stepping in or out. We therefore must assure the doors
// are closed before setting a new destination.
assert(!isDoorOpen());

// We've ruled out all the nasty cases, so we can now safely lock
// the doors and set the new destination.
lockDoors();
destination = newdestination;
}

// Someone pressed the emergency stop button in the elevator.
onStopButtonPressed() {
// To stop the elevator, we make it believe it is already exactly
// where it should be.
destination = getPosition();
}

// Elevator cabin reached its destination.
onDestinationReached() {
// We reached the destination, so we can unlock the doors.
unlockDoors();
}

=======================================

Bonus task 1: Find an implementation using also only one variable, but ameliorating as many of the problems of the above solution as possible.

Bonus task 2: Find a solution using at most n+1 variables (where n is the number of floors) that will satisfy most users. (Be aware that a the "normal" solution can't be implemented since there is only one call button per floor.)

Have fun! :)

kR Birgit

1 comment:

  1. Na, und? Was gibt's jetzt für schöne Fälle? Auf Anhieb seh ich nur, dass destination = getDestination() zum emergency stop ziemlich hässlich wirkt...

    Also, Antworten auf die Fragen? ;)

    ReplyDelete