working multiple missions
[des2015.git] / dsl / runtime / src / nl / ru / des / Arbitrator.java
1 package nl.ru.des;
2
3 import lejos.robotics.subsumption.Behavior;
4
5 /**
6 * Arbitrator controls which Behavior object will become active in a behavior
7 * control system. Make sure to call start() after the Arbitrator is
8 * instantiated.<br>
9 * This class has three major responsibilities: <br>
10 * 1. Determine the highest priority behavior that returns <b> true </b> to
11 * takeControl()<br>
12 * 2. Suppress the active behavior if its priority is less than highest
13 * priority. <br>
14 * 3. When the action() method exits, call action() on the Behavior of highest
15 * priority. <br>
16 * The Arbitrator assumes that a Behavior is no longer active when action()
17 * exits, <br>
18 * therefore it will only call suppress() on the Behavior whose action() method
19 * is running. <br>
20 * It can make consecutive calls of action() on the same Behavior. <br>
21 * Requirements for a Behavior: <br>
22 * When suppress() is called, terminate action() immediately. <br>
23 * When action() exits, the robot is in a safe state (e.g. motors stopped)
24 *
25 * @see Behavior
26 * @author Roger Glassey
27 */
28 public class Arbitrator {
29
30 private final int NONE = -1;
31 private Behavior[] _behavior;
32 // highest priority behavior that wants control ; set by start() used by
33 // monitor
34 private int _highestPriority = NONE;
35 private int _active = NONE; // active behavior; set by monitor, used by
36 // start();
37 private boolean _returnWhenInactive;
38 private boolean stop;
39 /**
40 * Monitor is an inner class. It polls the behavior array to find the
41 * behavior of hightst priority. If higher than the active behavior, it
42 * calls active.suppress()
43 */
44 private Monitor monitor;
45
46 /**
47 * Allocates an Arbitrator object and initializes it with an array of
48 * Behavior objects. The index of a behavior in this array is its priority
49 * level, so the behavior of the largest index has the highest the priority
50 * level. The behaviors in an Arbitrator can not be changed once the
51 * arbitrator is initialized.<BR>
52 * <B>NOTE:</B> Once the Arbitrator is initialized, the method start() must
53 * be called to begin the arbitration.
54 *
55 * @param behaviorList
56 * an array of Behavior objects.
57 * @param returnWhenInactive
58 * if <B>true</B>, the <B>start()</B> method returns when no
59 * Behavior is active.
60 */
61 public Arbitrator(Behavior[] behaviorList, boolean returnWhenInactive) {
62 _behavior = behaviorList;
63 _returnWhenInactive = returnWhenInactive;
64 stop = false;
65 monitor = new Monitor();
66 monitor.setDaemon(true);
67 }
68
69 /**
70 * Same as Arbitrator(behaviorList, false) Arbitrator start() never exits
71 *
72 * @param behaviorList
73 * An array of Behavior objects.
74 */
75 public Arbitrator(Behavior[] behaviorList) {
76 this(behaviorList, false);
77 }
78
79 /**
80 * This method starts the arbitration of Behaviors and runs an endless loop.
81 * <BR>
82 * Note: Arbitrator does not run in a separate thread. The start() method
83 * will never return unless <br>
84 * 1. no action() method is running and <br>
85 * 2. no behavior takeControl() returns <B> true </B> and <br>
86 * 3. the <i>returnWhenInacative </i> flag is true,
87 */
88 public void start() {
89 monitor.start();
90 while (_highestPriority == NONE) {
91 Thread.yield();// wait for some behavior to take contro
92 }
93 while (!stop) {
94 synchronized (monitor) {
95 if (_highestPriority != NONE) {
96 _active = _highestPriority;
97
98 } else if (_returnWhenInactive) {// no behavior wants to run
99 monitor.more = false;// 9 shut down monitor thread
100 return;
101 }
102 } // monitor released before action is called
103 if (_active != NONE) // _highestPrioirty could be NONE
104 {
105 _behavior[_active].action();
106 _active = NONE; // no active behavior at the moment
107 }
108 Thread.yield();
109 }
110 }
111
112 public void stop() {
113 this.monitor.more = false;
114 stop = true;
115 }
116
117 /**
118 * Finds the highest priority behavior that returns <B>true </B> to
119 * takeControl(); If this priority is higher than the active behavior, it
120 * calls active.suppress(). If there is no active behavior, calls suppress()
121 * on the most recently active behavior.
122 */
123 private class Monitor extends Thread {
124
125 boolean more = true;
126 int maxPriority = _behavior.length - 1;
127
128 public void run() {
129 while (more) {
130 // FIND HIGHEST PRIORITY BEHAVIOR THAT WANTS CONTROL
131 synchronized (this) {
132 _highestPriority = NONE;
133 int active_behavior = _active; // BB modded
134 if (active_behavior == NONE)
135 active_behavior = 0; // BB modded
136 for (int i = maxPriority; i >= active_behavior; i--) // BB
137 {
138 if (_behavior[i].takeControl()) {
139 _highestPriority = i;
140 break;
141 }
142 }
143 int active = _active;// local copy: avoid out of bounds
144 // error in 134
145 if (active != NONE && _highestPriority > active) {
146 _behavior[active].suppress();
147 }
148 } // end synchronize block - main thread can run now
149 Thread.yield();
150 }
151 }
152 }
153 }
154