001package jmri.jmrix.can.cbus.simulator;
002
003import javax.annotation.CheckForNull;
004
005import jmri.jmrix.can.CanReply;
006import jmri.jmrix.can.CanSystemConnectionMemo;
007import jmri.jmrix.can.cbus.CbusConstants;
008
009import jmri.jmrix.can.cbus.node.*;
010import jmri.jmrix.can.cbus.swing.simulator.NdPane;
011
012/**
013 * Simulating a MERG CBUS Node.
014 *
015 * @author Steve Young Copyright (C) 2018 2019
016 * @see CbusSimulator
017 * @since 4.15.2
018 */
019public class CbusDummyNode extends CbusNode {
020
021    private NdPane _pane;
022
023    /**
024     * Create a new CbusDummyNode.
025     * @param sysmemo System Connection to use, can be null.
026     * @param nodenumber the initial Node Number.
027     */
028    public CbusDummyNode( @CheckForNull CanSystemConnectionMemo sysmemo, int nodenumber ){
029        super( sysmemo, nodenumber );
030        super.setNodeInFLiMMode(false);
031        setCanId(sysmemo);
032        _pane = null;
033    }
034
035    /**
036     * Uses in-class CanListener
037     * {@inheritDoc}
038     */    
039    @Override
040    public CbusNodeCanListener getNewCanListener(){
041        canListener = new CbusDummyNodeCanListener(_memo,this);
042        return canListener;
043    }
044
045    private CbusDummyNodeCanListener canListener;
046
047    // total events on module
048    protected void sendNUMEV(){
049        CanReply r = new CanReply(4);
050        r.setElement(0, CbusConstants.CBUS_NUMEV);
051        r.setElement(1, getNodeNumber() >> 8);
052        r.setElement(2, getNodeNumber() & 0xff);
053        r.setElement(3, (Math.max(0, (getNodeEventManager().getTotalNodeEvents())) & 0xff ) );
054        send.sendWithDelay(r,canListener.getSendIn(),canListener.getSendOut(),canListener.getDelay());
055    }
056
057    protected void sendENRSP(){
058        int extraDelay = 5;
059        for (int i = 0; i < getNodeEventManager().getTotalNodeEvents(); i++) {
060            
061            CbusNodeEvent ndEv = getNodeEventManager().getNodeEventByArrayID(i);
062            if (ndEv==null){
063                break;
064            }
065            
066            if ( ndEv.getIndex()<0 ) {
067                ndEv.setIndex( getNodeEventManager().getNextFreeIndex() );
068            }
069            
070            CanReply r = new CanReply(8);
071            r.setElement(0, CbusConstants.CBUS_ENRSP);
072            r.setElement(1, getNodeNumber() >> 8);
073            r.setElement(2, getNodeNumber() & 0xff);
074            r.setElement(3, ndEv.getNn() >> 8);
075            r.setElement(4, ndEv.getNn() & 0xff);
076            r.setElement(5, ndEv.getEn() >> 8);
077            r.setElement(6, ndEv.getEn() & 0xff);
078            r.setElement(7, ndEv.getIndex() & 0xff);
079            send.sendWithDelay(r,canListener.getSendIn(),canListener.getSendOut(),canListener.getDelay() + ( extraDelay * i ) );
080        }
081    }
082
083    protected void sendNEVAL( int index, int varIndex ){
084        
085        CbusNodeEvent _ndEv = getNodeEventManager().getNodeEventByIndex(index);
086        
087        if ( index < 0 || index > 255 ){
088            sendCMDERR(7);
089        }
090        
091        // for future sim. of CMDERR5 support
092        // if (varIndex>40) {
093        //    
094        //    sendCMDERR(5);
095        //    return;
096        // }
097        
098        else if (_ndEv==null){
099            sendCMDERR(12);
100        }
101        else {
102            CanReply r = new CanReply(6);
103            r.setElement(0, CbusConstants.CBUS_NEVAL);
104            r.setElement(1, getNodeNumber() >> 8);
105            r.setElement(2, getNodeNumber() & 0xff);
106            r.setElement(3, index & 0xff);
107            r.setElement(4, varIndex & 0xff);
108            r.setElement(5, _ndEv.getEvVar(varIndex) & 0xff);
109            send.sendWithDelay(r,canListener.getSendIn(),canListener.getSendOut(),canListener.getDelay());
110        }
111    }
112
113    protected void sendPARAMS() {
114        CanReply r = new CanReply(8);
115        r.setElement(0, CbusConstants.CBUS_PARAMS);
116        r.setElement(1, getNodeParamManager().getParameter(1) & 0xff );
117        r.setElement(2, getNodeParamManager().getParameter(2) & 0xff );
118        r.setElement(3, getNodeParamManager().getParameter(3) & 0xff);
119        r.setElement(4, getNodeParamManager().getParameter(4) & 0xff);
120        r.setElement(5, getNodeParamManager().getParameter(5) & 0xff);
121        r.setElement(6, getNodeParamManager().getParameter(6) & 0xff);
122        r.setElement(7, getNodeParamManager().getParameter(7) & 0xff);
123        send.sendWithDelay(r,canListener.getSendIn(),canListener.getSendOut(),canListener.getDelay());
124    }
125
126    protected void sendPNN() {
127        CanReply r = new CanReply(6);
128        r.setElement(0, CbusConstants.CBUS_PNN);
129        r.setElement(1, getNodeNumber() >> 8);
130        r.setElement(2, getNodeNumber() & 0xff);
131        r.setElement(3, getNodeParamManager().getParameter(1) & 0xff );
132        r.setElement(4, getNodeParamManager().getParameter(3) & 0xff );
133        r.setElement(5, getNodeParamManager().getParameter(8) & 0xff );
134        send.sendWithDelay(r,canListener.getSendIn(),canListener.getSendOut(),canListener.getDelay());
135    }
136
137    // Parameter answer
138    protected void sendPARAN( int index ){
139        try {
140            CanReply r = new CanReply(5);
141            r.setElement(0, CbusConstants.CBUS_PARAN);
142            r.setElement(1, getNodeNumber() >> 8);
143            r.setElement(2, getNodeNumber() & 0xff);
144            r.setElement(3, index & 0xff);
145            r.setElement(4, getNodeParamManager().getParameter(index) & 0xff);
146            send.sendWithDelay(r,canListener.getSendIn(),canListener.getSendOut(),canListener.getDelay());
147        }
148        catch (ArrayIndexOutOfBoundsException e) {
149            sendCMDERR(9);
150        }
151    }
152
153    // NV Answer
154    protected void sendNVANS( int index ) {
155        try {
156            CanReply r = new CanReply(5);
157            r.setElement(0, CbusConstants.CBUS_NVANS);
158            r.setElement(1, getNodeNumber() >> 8);
159            r.setElement(2, getNodeNumber() & 0xff);
160            r.setElement(3, index & 0xff );
161            r.setElement(4, getNodeNvManager().getNV(index) & 0xff );
162            send.sendWithDelay(r,canListener.getSendIn(),canListener.getSendOut(),canListener.getDelay());
163        }
164        catch (ArrayIndexOutOfBoundsException e) {
165            sendCMDERR(10);
166        }
167    }
168
169    protected void setDummyNV(int index, int newval) {
170
171        // not per CBUS spec. however some modules do this...
172        if ( this.getnvWriteInLearnOnly() && !this.getNodeInLearnMode() ){
173            sendCMDERR(2);
174            return;
175        }
176
177        if ( newval<0 || newval > 255 ) {
178            sendCMDERR(12);
179            return;
180        }
181        
182        if (index==0) {
183            sendCMDERR(10);
184            return;
185        }
186        try {
187            getNodeNvManager().setNV(index,newval);
188            if ( getsendsWRACKonNVSET() ){
189                sendWRACK();
190            }
191        }
192        catch(ArrayIndexOutOfBoundsException e){
193            sendCMDERR(10);
194        }
195    }
196
197    protected void sendCMDERR(int errorId) {
198        CanReply r = new CanReply(4);
199        r.setElement(0, CbusConstants.CBUS_CMDERR);
200        r.setElement(1, getNodeNumber() >> 8);
201        r.setElement(2, getNodeNumber() & 0xff);
202        r.setElement(3, errorId & 0xff);
203        send.sendWithDelay(r,canListener.getSendIn(),canListener.getSendOut(),canListener.getDelay());
204    }
205
206    protected void sendWRACK(){
207        CanReply r = new CanReply(3);
208        r.setElement(0, CbusConstants.CBUS_WRACK);
209        r.setElement(1, getNodeNumber() >> 8);
210        r.setElement(2, getNodeNumber() & 0xff);        
211        send.sendWithDelay(r,canListener.getSendIn(),canListener.getSendOut(),canListener.getDelay());
212    }
213
214    // sim of FiLM Button
215    public void flimButton() {
216        // send request for node number
217        if ( getNodeParamManager().getParameter(3) >0 ) { // module type set
218            setNodeInSetupMode(true);
219            CanReply r = new CanReply(3);
220            r.setElement(0, CbusConstants.CBUS_RQNN);
221            r.setElement(1, getNodeNumber() >> 8);
222            r.setElement(2, getNodeNumber() & 0xff);
223            send.sendWithDelay(r,canListener.getSendIn(),canListener.getSendOut(),canListener.getDelay());
224        }
225    }
226
227    public void setPane(NdPane pane) {
228        _pane = pane;
229    }
230
231    protected void setDNN(int nn){
232        setNodeNumber(nn);
233        setNodeInFLiMMode(true);
234        setNodeInSetupMode(false);
235        if (_pane != null) {
236            _pane.updateNodeGui();
237        }
238        CanReply r = new CanReply(3);
239        r.setElement(0, CbusConstants.CBUS_NNACK);
240        r.setElement(1, getNodeNumber() >> 8);
241        r.setElement(2, getNodeNumber() & 0xff);
242        send.sendWithDelay(r,canListener.getSendIn(),canListener.getSendOut(),canListener.getDelay());
243    }
244
245    // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CbusDummyNode.class);
246
247}