001package jmri; 002 003import java.beans.PropertyChangeListener; 004import java.util.List; 005 006import javax.annotation.CheckForNull; 007import javax.annotation.Nonnull; 008 009/** 010 * Provide access to the hardware DCC decoder programming capability. 011 * <p> 012 * Programmers come in multiple types: 013 * <ul> 014 * <li>Global, previously "Service Mode" or on a programming track 015 * <li>Addressed, previously "Ops Mode" also known as "programming on the main" 016 * </ul> 017 * Different equipment may also require different programmers: 018 * <ul> 019 * <li>DCC CV programming, on service mode track or on the main 020 * <li>CBUS Node Variable programmers 021 * <li>LocoNet System Variable programmers 022 * <li>LocoNet Op Switch programmers 023 * <li>etc 024 * </ul> 025 * Depending on which type you have, only certain modes can be set. Valid modes 026 * are specified by the class static constants. 027 * <p> 028 * You get a Programmer object from a {@link GlobalProgrammerManager} or an 029 * {@link AddressedProgrammerManager}, which in turn can be located from the 030 * {@link InstanceManager}. 031 * <p> 032 * Starting in JMRI 3.5.5, the CV addresses are Strings for generality. The 033 * methods that use ints for CV addresses will later be deprecated. 034 * <p> 035 * Added possibility to supply CV value hint to the system 036 * <hr> 037 * This file is part of JMRI. 038 * <p> 039 * JMRI is free software; you can redistribute it and/or modify it under the 040 * terms of version 2 of the GNU General Public License as published by the Free 041 * Software Foundation. See the "COPYING" file for a copy of this license. 042 * <p> 043 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 044 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 045 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 046 * 047 * @see jmri.GlobalProgrammerManager 048 * @see jmri.AddressedProgrammerManager 049 * @author Bob Jacobsen Copyright (C) 2001, 2008, 2013 050 * @author Andrew Crosland (C) 2021 051 */ 052public interface Programmer extends jmri.Disposable { 053 054 /** 055 * A configurator for this programmer. 056 * It's used if some code in JMRI needs to get direct access to some part 057 * of a connection specific programmer. 058 * <P> 059 * Note! This class must not be the programmer itself. It should open up 060 * as little as possible of the programmer. Otherwise an hacker could 061 * potentially use this to circumvent the permission system. 062 */ 063 public interface Configurator { 064 } 065 066 /** 067 * Get the configurator of this programmer. 068 * @return the configurator if it exists, otherwise null 069 */ 070 @CheckForNull 071 default Configurator getConfigurator() { return null; } 072 073 /** 074 * Perform a CV write in the system-specific manner, and using the specified 075 * programming mode. 076 * <p> 077 * Handles a general address space through a String address. Each programmer 078 * defines the acceptable formats. 079 * <p> 080 * Note that this returns before the write is complete; you have to provide 081 * a ProgListener to hear about completion. For simplicity, expect the return to be on the 082 * <a href="http://jmri.org/help/en/html/doc/Technical/Threads.shtml">GUI thread</a>. 083 * <p> 084 * Exceptions will only be 085 * thrown at the start, not during the actual programming sequence. A 086 * typical exception would be due to an invalid mode (though that should be 087 * prevented earlier) 088 * 089 * @param CV the CV to write 090 * @param val the value to write 091 * @param p the listener that will be notified of the write 092 * @throws jmri.ProgrammerException if unable to communicate 093 */ 094 void writeCV(String CV, int val, ProgListener p) throws ProgrammerException; 095 096 /** 097 * Perform a CV read in the system-specific manner, and using the specified 098 * programming mode. 099 * <p> 100 * Handles a general address space through a String address. Each programmer 101 * defines the acceptable formats. 102 * <p> 103 * Note that this returns before the write is complete; you have to provide 104 * a ProgListener to hear about completion. For simplicity, expect the return to be on the 105 * <a href="http://jmri.org/help/en/html/doc/Technical/Threads.shtml">GUI thread</a>. 106 * <p> 107 * Exceptions will only be 108 * thrown at the start, not during the actual programming sequence. A 109 * typical exception would be due to an invalid mode (though that should be 110 * prevented earlier) 111 * 112 * @param CV the CV to read 113 * @param p the listener that will be notified of the read 114 * @throws jmri.ProgrammerException if unable to communicate 115 */ 116 void readCV(String CV, ProgListener p) throws ProgrammerException; 117 118 /** 119 * Perform a CV read in the system-specific manner, and using the specified 120 * programming mode, possibly using a hint of the current value to speed up 121 * programming. 122 * <p> 123 * Handles a general address space through a String address. Each programmer 124 * defines the acceptable formats. 125 * <p> 126 * On systems that support it, the startVal is a hint as to what the current 127 * value of the CV might be (e.g. the value from the roster). This could be 128 * verified immediately in direct byte mode to speed up the read process. 129 * <p> 130 * Note that this returns before the write is complete; you have to provide 131 * a ProgListener to hear about completion. For simplicity, expect the return to be on the 132 * <a href="http://jmri.org/help/en/html/doc/Technical/Threads.shtml">GUI thread</a>. 133 * <p> 134 * Defaults to the normal read method if not overridden in a specific implementation. 135 * <p> 136 * Exceptions will only be 137 * thrown at the start, not during the actual programming sequence. A 138 * typical exception would be due to an invalid mode (though that should be 139 * prevented earlier) 140 * 141 * @param CV the CV to read 142 * @param p the listener that will be notified of the read 143 * @param startVal a hint of what the current value might be, or 0 144 * @throws jmri.ProgrammerException if unable to communicate 145 */ 146 default void readCV(String CV, ProgListener p, int startVal) throws ProgrammerException { 147 readCV(CV, p); 148 } 149 150 /** 151 * Confirm the value of a CV using the specified programming mode. On some 152 * systems, this is faster than a read. 153 * <p> 154 * Handles a general address space through a String address. Each programmer 155 * defines the acceptable formats. 156 * <p> 157 * Note that this returns before the write is complete; you have to provide 158 * a ProgListener to hear about completion. For simplicity, expect the return to be on the 159 * <a href="http://jmri.org/help/en/html/doc/Technical/Threads.shtml">GUI thread</a>. 160 * <p> 161 * Exceptions will only be 162 * thrown at the start, not during the actual programming sequence. A 163 * typical exception would be due to an invalid mode (though that should be 164 * prevented earlier) 165 * 166 * @param CV the CV to confirm 167 * @param val the value to confirm 168 * @param p the listener that will be notified of the confirmation 169 * @throws jmri.ProgrammerException if unable to communicate 170 */ 171 void confirmCV(String CV, int val, ProgListener p) throws ProgrammerException; 172 173 /** 174 * Get the list of {@link ProgrammingMode} supported by this Programmer. If 175 * the order is significant, earlier modes are better. 176 * 177 * @return the list of supported modes or an empty list 178 */ 179 @Nonnull 180 List<ProgrammingMode> getSupportedModes(); 181 182 /** 183 * Set the programmer to a particular mode. 184 * <p> 185 * Mode is a bound parameter; mode changes fire listeners. 186 * <p> 187 * Only modes returned by {@link #getSupportedModes} are supported. If an 188 * invalid mode is requested, the active mode is unchanged. 189 * 190 * @param p a valid node returned by {@link #getSupportedModes()} or null; 191 * null is ignored if {@link #getSupportedModes()} is not empty 192 */ 193 void setMode(ProgrammingMode p); 194 195 /** 196 * Get the current programming mode 197 * 198 * @return the current mode or null if none is defined and no default mode 199 * is defined 200 */ 201 ProgrammingMode getMode(); 202 203 /** 204 * Checks the general read capability, regardless of mode 205 * 206 * @return true if the programmer is capable of reading; false otherwise 207 */ 208 boolean getCanRead(); 209 210 /** 211 * Checks the general read capability, regardless of mode, for a specific 212 * address 213 * 214 * @param addr the address to read 215 * @return true if the address can be read; false otherwise 216 */ 217 boolean getCanRead(String addr); 218 219 /** 220 * Checks the general write capability, regardless of mode 221 * 222 * @return true if the programmer is capable of writing; false otherwise 223 */ 224 boolean getCanWrite(); 225 226 /** 227 * Checks the general write capability, regardless of mode, for a specific 228 * address 229 * 230 * @param addr the address to write to 231 * @return true if the address can be written to; false otherwise 232 */ 233 boolean getCanWrite(String addr); 234 235 /** 236 * Learn about whether the programmer does any kind of verification of write 237 * operations 238 * 239 * @param addr A CV address to check (in case this varies with CV range) or 240 * null for any 241 * @return The confirmation behavior that can be counted on (might be better 242 * in some cases) 243 */ 244 @Nonnull 245 WriteConfirmMode getWriteConfirmMode(String addr); 246 247 enum WriteConfirmMode { 248 /** 249 * No verification available, writes are blind 250 */ 251 NotVerified, 252 /** 253 * Programmer signals error if there's no reply from the device 254 */ 255 DecoderReply, 256 /** 257 * Programmer does a read after write to verify 258 */ 259 ReadAfterWrite 260 } 261 262 /** 263 * wrapper to call {@link jmri.ProgListener#programmingOpReply} that verifies 264 * the specified progListener is not null. 265 * 266 * @param p listener to notify 267 * @param value result value 268 * @param status code from jmri.ProgListener 269 */ 270 default void notifyProgListenerEnd(ProgListener p, int value, int status) { 271 if ( p != null ) { 272 p.programmingOpReply(value, status); 273 } 274 } 275 276 void addPropertyChangeListener(PropertyChangeListener p); 277 278 void removePropertyChangeListener(PropertyChangeListener p); 279 280 // error handling on request is via exceptions 281 // results are returned via the ProgListener callback 282 @Nonnull 283 String decodeErrorCode(int i); 284 285 /** 286 * Free up system resources. 287 * Overriding classes should be capable of this being called 288 * multiple times as per the {@link jmri.Disposable} interface. 289 * {@inheritDoc} 290 */ 291 @Override 292 default void dispose() {} 293 294}