001package jmri; 002 003import java.util.List; 004 005import javax.annotation.CheckForNull; 006import javax.annotation.Nonnull; 007 008/** 009 * Sections represent a group of one or more connected Blocks that may be 010 * allocated to a train traveling in a given direction. 011 * <p> 012 * A Block may be in multiple Sections. All Blocks contained in a given section 013 * must be unique. Blocks are kept in order--the first block is connected to the 014 * second, the second is connected to the third, etc. 015 * <p> 016 * A Block in a Section must be connected to the Block before it (if there is 017 * one) and to the Block after it (if there is one), but may not be connected to 018 * any other Block in the Section. This restriction is enforced when a Section 019 * is created, and checked when a Section is loaded from disk. 020 * <p> 021 * A Section has a "direction" defined by the sequence in which Blocks are added 022 * to the Section. A train may run through a Section in either the forward 023 * direction (from first block to last block) or reverse direction (from last 024 * block to first block). 025 * <p> 026 * A Section has one or more EntryPoints. Each EntryPoint is a Path of one of 027 * the Blocks in the Section that defines a connection to a Block outside of the 028 * Section. EntryPoints are grouped into two lists: "forwardEntryPoints" - entry 029 * through which will result in a train traveling in the "forward" direction 030 * "reverseEntryPoints" - entry through which will result in a train traveling 031 * in the "reverse" direction Note that "forwardEntryPoints" are also reverse 032 * exit points, and vice versa. 033 * <p> 034 * A Section has one of the following states" FREE - available for allocation by 035 * a dispatcher FORWARD - allocated for travel in the forward direction REVERSE 036 * - allocated for travel in the reverse direction 037 * <p> 038 * A Section has an occupancy. A Section is OCCUPIED if any of its Blocks is 039 * OCCUPIED. A Section is UNOCCUPIED if all of its Blocks are UNOCCUPIED 040 * <p> 041 * A Section of may be allocated to only one train at a time, even if the trains 042 * are travelling in the same direction. If a Section has sufficient space for 043 * multiple trains travelling in the same direction it should be broken up into 044 * multiple Sections so the trains can follow each other through the original 045 * Section. 046 * <p> 047 * A Section may not contain any reverse loops. The track that is reversed in a 048 * reverse loop must be in a separate Section. 049 * <p> 050 * Each Section optionally carries two direction sensors, one for the forward 051 * direction and one for the reverse direction. These sensors force signals for 052 * travel in their respective directions to "RED" when they are active. When the 053 * Section is free, both the sensors are Active. These internal sensors follow 054 * the state of the Section, permitting signals to function normally in the 055 * direction of allocation. 056 * <p> 057 * Each Section optionally carries two stopping sensors, one for the forward 058 * direction and one for the reverse direction. These sensors change to active 059 * when a train traversing the Section triggers its sensing device. Stopping 060 * sensors are physical layout sensors, and may be either point sensors or 061 * occupancy sensors for short blocks at the end of the Section. A stopping 062 * sensor is used during automatic running to stop a train that has reached the 063 * end of its allocated Section. This is needed, for example, to allow a train 064 * to enter a passing siding and clear the track behind it. When not running 065 * automatically, these sensors may be used to light panel lights to notify the 066 * dispatcher that the train has reached the end of the Section. 067 * <p> 068 * This Section implementation provides for delayed initialization of blocks and 069 * direction sensors to be independent of order of items in panel files. 070 * 071 * @author Dave Duchamp Copyright (C) 2008,2010 072 * @author Bob Jacobsen Copyright (C) 2022 073 */ 074public interface Section extends NamedBean { 075 076 /** 077 * The value of {@link #getState()} if section is available for allocation. 078 */ 079 int FREE = 0x02; 080 081 /** 082 * The value of {@link #getState()} if section is allocated for travel in 083 * the forward direction. 084 */ 085 int FORWARD = 0x04; 086 087 /** 088 * The value of {@link #getState()} if section is allocated for travel in 089 * the reverse direction. 090 */ 091 int REVERSE = 0X08; 092 093 /** 094 * Value representing an occupied section. 095 */ 096 int OCCUPIED = Block.OCCUPIED; 097 098 /** 099 * Value representing an unoccupied section. 100 */ 101 int UNOCCUPIED = Block.UNOCCUPIED; 102 103 /** 104 * String constant for the property occupancy. 105 */ 106 String PROPERTY_OCCUPANCY = "occupancy"; 107 108 /** 109 * String constant for the property allocatedTo, fired when the value 110 * returned by {@link #getAllocatedTo()} changes. 111 */ 112 String PROPERTY_ALLOCATED_TO = "allocatedTo"; 113 114 /** 115 * Provide generic access to internal state. 116 * <p> 117 * This generally shouldn't be used by Java code; use the class-specific 118 * form instead (e.g. setCommandedState in Turnout). This is provided to 119 * make scripts access easier to read. 120 * <p> 121 * This isn't an exact override because it doesn't throw JmriException 122 * 123 * @param newState the state 124 */ 125 @Override 126 void setState(int newState); 127 128 /** 129 * Get the occupancy of a Section. 130 * 131 * @return {@link #OCCUPIED}, {@link #UNOCCUPIED}, or the state of the first 132 * block that is neither occupied or unoccupied 133 */ 134 int getOccupancy(); 135 136 String getForwardBlockingSensorName(); 137 138 @CheckForNull 139 Sensor getForwardBlockingSensor(); 140 141 Sensor setForwardBlockingSensorName(String forwardSensor); 142 143 void delayedSetForwardBlockingSensorName(String forwardSensor); 144 145 String getReverseBlockingSensorName(); 146 147 Sensor setReverseBlockingSensorName(String reverseSensor); 148 149 void delayedSetReverseBlockingSensorName(String reverseSensor); 150 151 @CheckForNull 152 Sensor getReverseBlockingSensor(); 153 154 @CheckForNull 155 Block getLastBlock(); 156 157 String getForwardStoppingSensorName(); 158 159 @CheckForNull 160 Sensor getForwardStoppingSensor(); 161 162 Sensor setForwardStoppingSensorName(String forwardSensor); 163 164 void delayedSetForwardStoppingSensorName(String forwardSensor); 165 166 String getReverseStoppingSensorName(); 167 168 @CheckForNull 169 Sensor setReverseStoppingSensorName(String reverseSensor); 170 171 void delayedSetReverseStoppingSensorName(String reverseSensor); 172 173 @CheckForNull 174 Sensor getReverseStoppingSensor(); 175 176 /** 177 * Add a Block to the Section. Block and sequence number must be unique 178 * within the Section. Block sequence numbers are set automatically as 179 * blocks are added. 180 * 181 * @param b the block to add 182 * @return true if Block was added or false if Block does not connect to the 183 * current Block, or the Block is not unique. 184 */ 185 boolean addBlock(Block b); 186 187 void delayedAddBlock(String blockName); 188 189 /** 190 * Get a list of blocks in this section 191 * 192 * @return a list of blocks 193 */ 194 @Nonnull 195 List<Block> getBlockList(); 196 197 /** 198 * Gets the number of Blocks in this Section 199 * 200 * @return the number of blocks 201 */ 202 int getNumBlocks(); 203 204 /** 205 * Get the scale length of Section. Length of the Section is calculated by 206 * summing the lengths of all Blocks in the section. If all Block lengths 207 * have not been entered, length will not be correct. 208 * 209 * @param meters true to return length in meters, false to use feet 210 * @param scale the scale; one of {@link jmri.Scale} 211 * @return the scale length 212 */ 213 float getLengthF(boolean meters, Scale scale); 214 215 int getLengthI(boolean meters, Scale scale); 216 217 /** 218 * Gets the actual length of the Section without any scaling 219 * 220 * @return the real length in millimeters 221 */ 222 int getActualLength(); 223 224 /** 225 * Get Block by its Sequence number in the Section. 226 * 227 * @param seqNumber the sequence number 228 * @return the block or null if the sequence number is invalid 229 */ 230 @CheckForNull 231 Block getBlockBySequenceNumber(int seqNumber); 232 233 /** 234 * Get the sequence number of a Block. 235 * 236 * @param b the block to get the sequence of 237 * @return the sequence number of b or -1 if b is not in the Section 238 */ 239 int getBlockSequenceNumber(Block b); 240 241 /** 242 * Remove all Blocks, Block Listeners, and Entry Points 243 */ 244 void removeAllBlocksFromSection(); 245 246 @CheckForNull 247 Block getEntryBlock(); 248 249 @CheckForNull 250 Block getNextBlock(); 251 252 @CheckForNull 253 Block getExitBlock(); 254 255 boolean containsBlock(Block b); 256 257 boolean connectsToBlock(Block b); 258 259 String getBeginBlockName(); 260 261 String getEndBlockName(); 262 263 void addToForwardList(EntryPoint ep); 264 265 void addToReverseList(EntryPoint ep); 266 267 void removeEntryPoint(EntryPoint ep); 268 269 @Nonnull 270 List<EntryPoint> getForwardEntryPointList(); 271 272 @Nonnull 273 List<EntryPoint> getReverseEntryPointList(); 274 275 @Nonnull 276 List<EntryPoint> getEntryPointList(); 277 278 boolean isForwardEntryPoint(EntryPoint ep); 279 280 boolean isReverseEntryPoint(EntryPoint ep); 281 282 /** 283 * Get the EntryPoint for entry from the specified Section for travel in 284 * specified direction. 285 * 286 * @param s the section 287 * @param dir the direction of travel; one of {@link #FORWARD} or 288 * {@link #REVERSE} 289 * @return the entry point or null if not found 290 */ 291 @CheckForNull 292 EntryPoint getEntryPointFromSection(Section s, int dir); 293 294 /** 295 * Get the EntryPoint for exit to specified Section for travel in the 296 * specified direction. 297 * 298 * @param s the section 299 * @param dir the direction of travel; one of {@link #FORWARD} or 300 * {@link #REVERSE} 301 * @return the entry point or null if not found 302 */ 303 @CheckForNull 304 EntryPoint getExitPointToSection(Section s, int dir); 305 306 /** 307 * Get the EntryPoint for entry from the specified Block for travel in the 308 * specified direction. 309 * 310 * @param b the block 311 * @param dir the direction of travel; one of {@link #FORWARD} or 312 * {@link #REVERSE} 313 * @return the entry point or null if not found 314 */ 315 @CheckForNull 316 EntryPoint getEntryPointFromBlock(Block b, int dir); 317 318 /** 319 * Get the EntryPoint for exit to the specified Block for travel in the 320 * specified direction. 321 * 322 * @param b the block 323 * @param dir the direction of travel; one of {@link #FORWARD} or 324 * {@link #REVERSE} 325 * @return the entry point or null if not found 326 */ 327 @CheckForNull 328 EntryPoint getExitPointToBlock(Block b, int dir); 329 330 /** 331 * Place direction sensors in SSL for all Signal Heads in this Section if 332 * the Sensors are not already present in the SSL. 333 * <p> 334 * Only anchor point block boundaries that have assigned signals are 335 * considered. Only turnouts that have assigned signals are considered. Only 336 * level crossings that have assigned signals are considered. Turnouts and 337 * anchor points without signals are counted, and reported in warning 338 * messages during this procedure, if there are any missing signals. 339 * <p> 340 * If this method has trouble, an error message is placed in the log 341 * describing the trouble. 342 * 343 * @return the number or errors placing sensors; 1 is returned if no 344 * direction sensor is defined for this section 345 */ 346 int placeDirectionSensors(); 347 348 /** 349 * Validate the Section. This checks block connectivity, warns of redundant 350 * EntryPoints, and otherwise checks internal consistency of the Section. An 351 * appropriate error message is logged if a problem is found. This method 352 * assumes that Block Paths are correctly initialized. 353 * 354 * @return an error description or empty string if there are no errors 355 */ 356 String validate(); 357 358 /** 359 * Set/reset the display to use alternate color for unoccupied blocks in 360 * this section. If Layout Editor panel is not present, Layout Blocks will 361 * not be present, and nothing will be set. 362 * 363 * @param set true to use alternate unoccupied color; false otherwise 364 */ 365 void setAlternateColor(boolean set); 366 367 /** 368 * Set/reset the display to use alternate color for unoccupied blocks in 369 * this Section. If the Section already contains an active block, then the 370 * alternative color will be set from the active block, if no active block 371 * is found or we are clearing the alternative color then all the blocks in 372 * the Section will be set. If Layout Editor panel is not present, Layout 373 * Blocks will not be present, and nothing will be set. 374 * 375 * @param set true to use alternate unoccupied color; false otherwise 376 */ 377 void setAlternateColorFromActiveBlock(boolean set); 378 379 /** 380 * Set the block values for blocks in this Section. 381 * 382 * @param name the value to set all blocks to 383 */ 384 void setNameInBlocks(String name); 385 386 /** 387 * Set the block values for blocks in this Section. 388 * 389 * @param value the name to set block values to 390 */ 391 void setNameInBlocks(Object value); 392 393 void setNameFromActiveBlock(Object value); 394 395 /** 396 * Clear the block values for blocks in this Section. 397 */ 398 void clearNameInUnoccupiedBlocks(); 399 400 /** 401 * Suppress the update of a memory variable when a block goes to unoccupied, 402 * so the text set above doesn't get wiped out. 403 * 404 * @param set true to suppress the update; false otherwise 405 */ 406 void suppressNameUpdate(boolean set); 407 408 @SuppressWarnings("hiding") // Field has same name as a field in the super class 409 enum SectionType { 410 DYNAMICADHOC, // Created on an as required basis, not to be saved. 411 USERDEFINED, // Default Save all the information 412 SIGNALMASTLOGIC // Save only the name, blocks will be added by the signalmast logic 413 } 414 SectionType USERDEFINED = SectionType.USERDEFINED; 415 SectionType SIGNALMASTLOGIC = SectionType.SIGNALMASTLOGIC; 416 SectionType DYNAMICADHOC = SectionType.DYNAMICADHOC; 417 418 /** 419 * Set Section Type. 420 * <ul> 421 * <li>USERDEFINED - Default Save all the information. 422 * <li>SIGNALMASTLOGIC - Save only the name, blocks will be added by the SignalMast logic. 423 * <li>DYNAMICADHOC - Created on an as required basis, not to be saved. 424 * </ul> 425 * @param type constant of section type. 426 */ 427 void setSectionType(SectionType type); 428 429 /** 430 * Get Section Type. 431 * Defaults to USERDEFINED. 432 * @return constant of section type. 433 */ 434 SectionType getSectionType(); 435 436 /** 437 * Get who this Section is allocated to, for example the Dispatcher train 438 * holding it. Signal Mast Logic uses this to tell a block reserved for the 439 * train approaching a mast from one reserved for another train. 440 * 441 * @return the holder, or null if the Section is not allocated or the 442 * holder is not known 443 */ 444 default Object getAllocatedTo() { 445 return null; 446 } 447 448 /** 449 * Set who this Section is allocated to. Holders are compared by identity. 450 * The holder is cleared when the Section is set {@link #FREE}. 451 * 452 * @param holder the holder, or null when the Section is released 453 */ 454 default void setAllocatedTo(Object holder) { 455 } 456 457}