001package jmri.jmrix.can.cbus.node;
002
003// import javax.annotation.Nonnull;
004import javax.annotation.CheckForNull;
005
006import jmri.jmrix.can.CanSystemConnectionMemo;
007
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011/**
012 * Class to represent a node.
013 *
014 * @author Steve Young Copyright (C) 2019
015 */
016public class CbusNode extends CbusBasicNodeWithMgrsCommandStation {
017    
018    private int _flags;
019    private String _userComment;
020    private boolean _sendsWRACKonNVSET;
021    private boolean _nvWriteInLearnOnly;
022    private boolean _liveUpdate;
023    public static int SINGLE_MESSAGE_TIMEOUT_TIME = 1500;
024    public static int BOOT_PROG_TIMEOUT_FAST = 10;
025    public static int BOOT_PROG_TIMEOUT_SLOW = 50;
026    public static int BOOT_LONG_TIMEOUT_TIME = 1500;
027    private String _nodeNameFromName;
028    private String resyncName = null;
029    
030    /**
031     * Create a new CbusNode
032     *
033     * @param connmemo The CAN Connection to use
034     * @param nodenumber The Node Number
035     */
036    public CbusNode ( @CheckForNull CanSystemConnectionMemo connmemo, int nodenumber ){
037        super(connmemo,nodenumber);
038        
039        _sendsWRACKonNVSET = true;
040        _nvWriteInLearnOnly = false;
041        _liveUpdate = false;
042        _flags = -1;
043        _userComment = "";
044        _nodeNameFromName = "";
045    }
046    
047    /**
048     * Set Node UserName only if UserName not currently set
049     * used in RestoreFromFCU
050     * @param newName UserName of the node
051     */
052    public void setNameIfNoName( String newName ) {
053        if ( getUserName().isEmpty() ){
054            setUserName(newName);
055        }
056    }
057    
058    /**
059     * Get Module Type Name from a previous NAME OPC response
060     * Used when a module type is not identified within JMRI.
061     * @return Module type name, NOT prefixed with CAN or ETH, may be empty.
062     */
063    public String getNodeNameFromName(){
064        return _nodeNameFromName;
065    }
066    
067    /**
068     * Set Module Type Name
069     * Used when a module is not identified within JMRI so the NAME is requested.
070     * @param newName The module type name, should NOT be prefixed with CAN or ETH
071     */
072    public void setNodeNameFromName( String newName ){
073        if (newName==null) {
074            newName = "";
075        }
076        _nodeNameFromName = newName;
077        notifyPropertyChangeListener("NAMECHANGE", null, null);
078    }
079    
080    /**
081     * Set the Node Flags
082     * <p>
083     * Bit 0: Consumer
084     * Bit 1: Producer
085     * Bit 2: FLiM Mode
086     * Bit 3: The module supports bootloading
087     * Bit 4: The module can consume its own produced events
088     * Bit 5: Module is in learn mode - CBUS Spec 6c
089     *
090     * @param flags the int value of the flags.
091     */
092    public void setNodeFlags(int flags) {
093        _flags = flags;
094        // if ( ( ( _flags >> 0 ) & 1 ) == 1 ){
095        //     log.debug("Consumer node");
096        // }
097        
098        if ( ( ( _flags >> 2 ) & 1 ) == 0 ){
099            getNodeBackupManager().setNodeInSlim();
100            getNodeEventManager().resetNodeEventsToZero(); // sets num events to 0
101        }
102        
103        if ( ( ( _flags >> 5 ) & 1 ) == 1 ){
104            log.debug("Node in learn mode");
105            setNodeInLearnMode(true);
106        }
107        notifyPropertyChangeListener("PARAMETER", null, null);
108    }
109    
110    /**
111     * Get Node Flags
112     * <p>
113     * Captured from a PNN node response
114     * @return flags in int form, will need decoding to bit, -1 if unset
115     */
116    public int getNodeFlags() {
117        return _flags;
118    }
119    
120    /**
121     * Get name of node being resync'ed
122     * 
123     * @return String node name
124     */
125    public String getResyncName() {
126        return resyncName;
127    }
128    
129    /**
130     * Save module name when Resync is in progress
131     *
132     * Resync resets all node parameters, etc. To re0display the NV edit GUI
133     * before the resync completes we save a copy of the name of the node.
134     */
135    protected void saveForResync() {
136        if (!CbusNodeConstants.getModuleType(this.getNodeParamManager().getParameter(1),this.getNodeParamManager().getParameter(3)).isEmpty() ){
137            resyncName =  CbusNodeConstants.getModuleType(this.getNodeParamManager().getParameter(1),this.getNodeParamManager().getParameter(3));
138        } else {
139            resyncName = null;
140        }
141    }
142    
143    /**
144     * Resets NV's, Events and Parameters
145     *
146     */
147    protected void resetNodeAll() {
148        getNodeNvManager().reset();
149        getNodeEventManager().resetNodeEvents();
150        getNodeParamManager().clearParameters();
151        getNodeTimerManager().resetTimeOutCounts();
152        notifyPropertyChangeListener("PARAMETER", null, null);
153    }
154
155    /**
156     * Get a Node User Comment
157     * @return user generated comment string
158     *
159     */
160    public String getUserComment() {
161        return _userComment;
162    }
163    
164    /**
165     * Set a Node User Comment
166     * <p>
167     * Typically output from JTextArea
168     * <p>
169     * If a backup has completed for this session, updates the xml file
170     *
171     * @param comment user comment
172     */
173    public void setUserComment(String comment) {
174        _userComment = comment;
175        if (getNodeBackupManager().getBackupStarted()) {
176            if (!getNodeBackupManager().doStore(false,getNodeStats().hasLoadErrors()) ) {
177                log.error("Unable to save User Comment to Node Backup File");
178            }
179        }
180    }
181    
182    /**
183     * Custom toString reports the Node Number Name
184     * @return string eg "1234 UserName" or "256 CANPAN" if no UserName. No trailing space.
185     *
186     * {@inheritDoc} 
187     */
188    @Override
189    public String toString(){
190        return getNodeStats().getNodeNumberName();
191    }
192    
193    /**
194     * Reports just the name, not the user name.
195     *
196     * @return string eg "CANPAN"
197     *
198     */
199    public String getName(){
200        return getNodeStats().getNodeTypeName();
201    }
202    
203    /**
204     * Set node on network
205     * @param isFound false if not on network
206     */
207    protected void nodeOnNetwork( boolean isFound ) {
208        
209        if (!isFound) {
210            getNodeTimerManager().cancelTimers();
211            getNodeParamManager().setParameters( new int[]{0} );
212            
213            // set events to 0 as if parameters cannot be fetched, 
214            // no point in attempting anything else
215            getNodeEventManager().resetNodeEventsToZero();
216            // if not already set as not on network, set that now
217            if ( !(getNodeBackupManager().getSessionBackupStatus() == CbusNodeConstants.BackupType.NOTONNETWORK )) {
218                getNodeBackupManager().nodeNotOnNetwork();
219            }
220            notifyPropertyChangeListener("BACKUPS", null, null);
221        }
222    }
223    
224    /**
225     * DO NOT RELY ON, TO BE REMOVED IN FUTURE RELEASE
226     * when the NV will automatically be queried if no NVSET is received
227     *
228     * @param sendsWRACK true if sends
229     */
230    public void setsendsWRACKonNVSET( Boolean sendsWRACK ){
231        _sendsWRACKonNVSET = sendsWRACK;
232    }
233    
234    
235    
236    /**
237     * DO NOT RELY ON, TO BE REMOVED IN FUTURE RELEASE
238     * when the NV will automatically be queried if no NVSET is received
239     *
240     * @return true if sends WRACK, else false
241     */
242    public boolean getsendsWRACKonNVSET() {
243        return _sendsWRACKonNVSET;
244    }
245    
246    
247    /**
248     * CANSERVO8C and related modules only accept NV writes in learn mode.
249     * 
250     * This was used by the MERG FCU to update servo positions in "real time" in
251     * response to interaction with the GUI. Call this method to indicate that a
252     * node must be in learn mode to support NV writes.
253     * 
254     * @param nvWriteInLearn true if node requires to be in learn mode for NV writes
255     */
256    public void setnvWriteInLearnOnly( Boolean nvWriteInLearn ){
257        _nvWriteInLearnOnly = nvWriteInLearn;
258    }
259    
260    /**
261     * CANSERVO8C and related modules only accept NV writes in learn mode.
262     * 
263     * This was used by the MERG FCU to update servo positions in "real time" in
264     * response to interaction with the GUI. Call this method to query if a
265     * node must be in learn mode to support NV writes.
266     * 
267     * @return true if sends WRACK, else false
268     */
269    public boolean getnvWriteInLearnOnly() {
270        return _nvWriteInLearnOnly;
271    }
272    
273    /**
274     * Set flag to say node is in live update mode.
275     * 
276     * @param liveUpdate true if in live update mode
277     */
278    public void setliveUpdate(boolean liveUpdate) {
279        _liveUpdate = liveUpdate;
280    }
281    
282    /**
283     * Get live update mode
284     * 
285     * @return true in live update
286     */
287    public boolean getliveUpdate() {
288        return _liveUpdate;
289    }
290    
291    private static final Logger log = LoggerFactory.getLogger(CbusNode.class);
292    
293}