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