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 * Provide generic access to internal state. 110 * <p> 111 * This generally shouldn't be used by Java code; use the class-specific 112 * form instead (e.g. setCommandedState in Turnout). This is provided to 113 * make scripts access easier to read. 114 * <p> 115 * This isn't an exact override because it doesn't throw JmriException 116 * 117 * @param newState the state 118 */ 119 @Override 120 void setState(int newState); 121 122 /** 123 * Get the occupancy of a Section. 124 * 125 * @return {@link #OCCUPIED}, {@link #UNOCCUPIED}, or the state of the first 126 * block that is neither occupied or unoccupied 127 */ 128 int getOccupancy(); 129 130 String getForwardBlockingSensorName(); 131 132 @CheckForNull 133 Sensor getForwardBlockingSensor(); 134 135 Sensor setForwardBlockingSensorName(String forwardSensor); 136 137 void delayedSetForwardBlockingSensorName(String forwardSensor); 138 139 String getReverseBlockingSensorName(); 140 141 Sensor setReverseBlockingSensorName(String reverseSensor); 142 143 void delayedSetReverseBlockingSensorName(String reverseSensor); 144 145 @CheckForNull 146 Sensor getReverseBlockingSensor(); 147 148 @CheckForNull 149 Block getLastBlock(); 150 151 String getForwardStoppingSensorName(); 152 153 @CheckForNull 154 Sensor getForwardStoppingSensor(); 155 156 Sensor setForwardStoppingSensorName(String forwardSensor); 157 158 void delayedSetForwardStoppingSensorName(String forwardSensor); 159 160 String getReverseStoppingSensorName(); 161 162 @CheckForNull 163 Sensor setReverseStoppingSensorName(String reverseSensor); 164 165 void delayedSetReverseStoppingSensorName(String reverseSensor); 166 167 @CheckForNull 168 Sensor getReverseStoppingSensor(); 169 170 /** 171 * Add a Block to the Section. Block and sequence number must be unique 172 * within the Section. Block sequence numbers are set automatically as 173 * blocks are added. 174 * 175 * @param b the block to add 176 * @return true if Block was added or false if Block does not connect to the 177 * current Block, or the Block is not unique. 178 */ 179 boolean addBlock(Block b); 180 181 void delayedAddBlock(String blockName); 182 183 /** 184 * Get a list of blocks in this section 185 * 186 * @return a list of blocks 187 */ 188 @Nonnull 189 List<Block> getBlockList(); 190 191 /** 192 * Gets the number of Blocks in this Section 193 * 194 * @return the number of blocks 195 */ 196 int getNumBlocks(); 197 198 /** 199 * Get the scale length of Section. Length of the Section is calculated by 200 * summing the lengths of all Blocks in the section. If all Block lengths 201 * have not been entered, length will not be correct. 202 * 203 * @param meters true to return length in meters, false to use feet 204 * @param scale the scale; one of {@link jmri.Scale} 205 * @return the scale length 206 */ 207 float getLengthF(boolean meters, Scale scale); 208 209 int getLengthI(boolean meters, Scale scale); 210 211 /** 212 * Gets the actual length of the Section without any scaling 213 * 214 * @return the real length in millimeters 215 */ 216 int getActualLength(); 217 218 /** 219 * Get Block by its Sequence number in the Section. 220 * 221 * @param seqNumber the sequence number 222 * @return the block or null if the sequence number is invalid 223 */ 224 @CheckForNull 225 Block getBlockBySequenceNumber(int seqNumber); 226 227 /** 228 * Get the sequence number of a Block. 229 * 230 * @param b the block to get the sequence of 231 * @return the sequence number of b or -1 if b is not in the Section 232 */ 233 int getBlockSequenceNumber(Block b); 234 235 /** 236 * Remove all Blocks, Block Listeners, and Entry Points 237 */ 238 void removeAllBlocksFromSection(); 239 240 @CheckForNull 241 Block getEntryBlock(); 242 243 @CheckForNull 244 Block getNextBlock(); 245 246 @CheckForNull 247 Block getExitBlock(); 248 249 boolean containsBlock(Block b); 250 251 boolean connectsToBlock(Block b); 252 253 String getBeginBlockName(); 254 255 String getEndBlockName(); 256 257 void addToForwardList(EntryPoint ep); 258 259 void addToReverseList(EntryPoint ep); 260 261 void removeEntryPoint(EntryPoint ep); 262 263 @Nonnull 264 List<EntryPoint> getForwardEntryPointList(); 265 266 @Nonnull 267 List<EntryPoint> getReverseEntryPointList(); 268 269 @Nonnull 270 List<EntryPoint> getEntryPointList(); 271 272 boolean isForwardEntryPoint(EntryPoint ep); 273 274 boolean isReverseEntryPoint(EntryPoint ep); 275 276 /** 277 * Get the EntryPoint for entry from the specified Section for travel in 278 * specified direction. 279 * 280 * @param s the section 281 * @param dir the direction of travel; one of {@link #FORWARD} or 282 * {@link #REVERSE} 283 * @return the entry point or null if not found 284 */ 285 @CheckForNull 286 EntryPoint getEntryPointFromSection(Section s, int dir); 287 288 /** 289 * Get the EntryPoint for exit to specified Section for travel in the 290 * specified direction. 291 * 292 * @param s the section 293 * @param dir the direction of travel; one of {@link #FORWARD} or 294 * {@link #REVERSE} 295 * @return the entry point or null if not found 296 */ 297 @CheckForNull 298 EntryPoint getExitPointToSection(Section s, int dir); 299 300 /** 301 * Get the EntryPoint for entry from the specified Block for travel in the 302 * specified direction. 303 * 304 * @param b the block 305 * @param dir the direction of travel; one of {@link #FORWARD} or 306 * {@link #REVERSE} 307 * @return the entry point or null if not found 308 */ 309 @CheckForNull 310 EntryPoint getEntryPointFromBlock(Block b, int dir); 311 312 /** 313 * Get the EntryPoint for exit to the specified Block for travel in the 314 * specified direction. 315 * 316 * @param b the block 317 * @param dir the direction of travel; one of {@link #FORWARD} or 318 * {@link #REVERSE} 319 * @return the entry point or null if not found 320 */ 321 @CheckForNull 322 EntryPoint getExitPointToBlock(Block b, int dir); 323 324 /** 325 * Place direction sensors in SSL for all Signal Heads in this Section if 326 * the Sensors are not already present in the SSL. 327 * <p> 328 * Only anchor point block boundaries that have assigned signals are 329 * considered. Only turnouts that have assigned signals are considered. Only 330 * level crossings that have assigned signals are considered. Turnouts and 331 * anchor points without signals are counted, and reported in warning 332 * messages during this procedure, if there are any missing signals. 333 * <p> 334 * If this method has trouble, an error message is placed in the log 335 * describing the trouble. 336 * 337 * @return the number or errors placing sensors; 1 is returned if no 338 * direction sensor is defined for this section 339 */ 340 int placeDirectionSensors(); 341 342 /** 343 * Validate the Section. This checks block connectivity, warns of redundant 344 * EntryPoints, and otherwise checks internal consistency of the Section. An 345 * appropriate error message is logged if a problem is found. This method 346 * assumes that Block Paths are correctly initialized. 347 * 348 * @return an error description or empty string if there are no errors 349 */ 350 String validate(); 351 352 /** 353 * Set/reset the display to use alternate color for unoccupied blocks in 354 * this section. If Layout Editor panel is not present, Layout Blocks will 355 * not be present, and nothing will be set. 356 * 357 * @param set true to use alternate unoccupied color; false otherwise 358 */ 359 void setAlternateColor(boolean set); 360 361 /** 362 * Set/reset the display to use alternate color for unoccupied blocks in 363 * this Section. If the Section already contains an active block, then the 364 * alternative color will be set from the active block, if no active block 365 * is found or we are clearing the alternative color then all the blocks in 366 * the Section will be set. If Layout Editor panel is not present, Layout 367 * Blocks will not be present, and nothing will be set. 368 * 369 * @param set true to use alternate unoccupied color; false otherwise 370 */ 371 void setAlternateColorFromActiveBlock(boolean set); 372 373 /** 374 * Set the block values for blocks in this Section. 375 * 376 * @param name the value to set all blocks to 377 */ 378 void setNameInBlocks(String name); 379 380 /** 381 * Set the block values for blocks in this Section. 382 * 383 * @param value the name to set block values to 384 */ 385 void setNameInBlocks(Object value); 386 387 void setNameFromActiveBlock(Object value); 388 389 /** 390 * Clear the block values for blocks in this Section. 391 */ 392 void clearNameInUnoccupiedBlocks(); 393 394 /** 395 * Suppress the update of a memory variable when a block goes to unoccupied, 396 * so the text set above doesn't get wiped out. 397 * 398 * @param set true to suppress the update; false otherwise 399 */ 400 void suppressNameUpdate(boolean set); 401 402 @SuppressWarnings("hiding") // Field has same name as a field in the super class 403 enum SectionType { 404 DYNAMICADHOC, // Created on an as required basis, not to be saved. 405 USERDEFINED, // Default Save all the information 406 SIGNALMASTLOGIC // Save only the name, blocks will be added by the signalmast logic 407 } 408 SectionType USERDEFINED = SectionType.USERDEFINED; 409 SectionType SIGNALMASTLOGIC = SectionType.SIGNALMASTLOGIC; 410 SectionType DYNAMICADHOC = SectionType.DYNAMICADHOC; 411 412 /** 413 * Set Section Type. 414 * <ul> 415 * <li>USERDEFINED - Default Save all the information. 416 * <li>SIGNALMASTLOGIC - Save only the name, blocks will be added by the SignalMast logic. 417 * <li>DYNAMICADHOC - Created on an as required basis, not to be saved. 418 * </ul> 419 * @param type constant of section type. 420 */ 421 void setSectionType(SectionType type); 422 423 /** 424 * Get Section Type. 425 * Defaults to USERDEFINED. 426 * @return constant of section type. 427 */ 428 SectionType getSectionType(); 429 430}