001package jmri.jmrix.can.cbus;
002
003import jmri.implementation.AbstractLight;
004import jmri.jmrix.can.CanListener;
005import jmri.jmrix.can.CanMessage;
006import jmri.jmrix.can.CanReply;
007import jmri.jmrix.can.TrafficController;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011/**
012 * Light implementation for CBUS connections.
013 *
014 * @author Matthew Harris Copyright (C) 2015
015 */
016public class CbusLight extends AbstractLight implements CanListener, CbusEventInterface {
017
018    private CbusAddress addrOn;   // go to on state
019    private CbusAddress addrOff;   // go to off state
020
021    protected CbusLight(String prefix, String address, TrafficController tc) {
022        super(prefix + "L" + address);
023        this.tc = tc;
024        init(address);
025    }
026
027    private final TrafficController tc;
028
029    /**
030     * Common initialization for both constructors.
031     * <p>
032     *
033     */
034    private void init(String address) {
035        // build local addresses
036        CbusAddress a = new CbusAddress(address);
037        CbusAddress[] v = a.split();
038        switch (v.length) {
039            case 0:
040                log.error("Did not find usable system name: {}", address);
041                return;
042            case 1:
043                addrOn = v[0];
044                // need to complement here for addr 1
045                // so address _must_ start with address + or -
046                if (address.startsWith("+")) {
047                    addrOff = new CbusAddress("-" + address.substring(1));
048                } else if (address.startsWith("-")) {
049                    addrOff = new CbusAddress("+" + address.substring(1));
050                } else {
051                    log.error("can't make 2nd event from systemname {}", address);
052                    return;
053                }
054                break;
055            case 2:
056                addrOn = v[0];
057                addrOff = v[1];
058                break;
059            default:
060                log.error("Can't parse CbusLight system name: {}", address);
061                return;
062        }
063        // connect
064        addTc(tc);
065    }
066
067    /**
068     * Handle a request to change state by sending CBUS events.
069     *
070     */
071    @Override
072    protected void doNewState(int oldState, int newState) {
073        CanMessage m;
074        switch (newState) {
075            case ON:
076                m = addrOn.makeMessage(tc.getCanid());
077                CbusMessage.setPri(m, CbusConstants.DEFAULT_DYNAMIC_PRIORITY * 4 + CbusConstants.DEFAULT_MINOR_PRIORITY);
078                tc.sendCanMessage(m, this);
079                break;
080            case OFF:
081                m = addrOff.makeMessage(tc.getCanid());
082                CbusMessage.setPri(m, CbusConstants.DEFAULT_DYNAMIC_PRIORITY * 4 + CbusConstants.DEFAULT_MINOR_PRIORITY);
083                tc.sendCanMessage(m, this);
084                break;
085            default:
086                log.warn("illegal state requested for Light: {}", getSystemName());
087                break;
088        }
089    }
090
091    /** {@inheritDoc} */
092    @Override
093    public void requestUpdateFromLayout() {
094        CanMessage m = addrOn.makeMessage(tc.getCanid());
095        m.setOpCode( CbusOpCodes.isShortEvent(CbusMessage.getOpcode(m)) ? CbusConstants.CBUS_ASRQ : CbusConstants.CBUS_AREQ);
096        CbusMessage.setPri(m, CbusConstants.DEFAULT_DYNAMIC_PRIORITY * 4 + CbusConstants.DEFAULT_MINOR_PRIORITY);
097        tc.sendCanMessage(m, this);
098    }
099    
100    /** {@inheritDoc} */
101    @Override
102    public void message(CanMessage f) {
103        if ( f.extendedOrRtr() ) {
104            return;
105        }
106        if (addrOn.match(f)) {
107            notifyStateChange(getState(), ON);
108        } else if (addrOff.match(f)) {
109            notifyStateChange(getState(), OFF);
110        }
111    }
112
113    /** {@inheritDoc} */
114    @Override
115    public void reply(CanReply origf) {
116        if ( origf.extendedOrRtr() ) {
117            return;
118        }
119        // convert response events to normal
120        CanReply f = CbusMessage.opcRangeToStl(origf);
121        if (addrOn.match(f)) {
122            notifyStateChange(getState(), ON);
123        } else if (addrOff.match(f)) {
124            notifyStateChange(getState(), OFF);
125        }
126    }
127    
128    /**
129     * Get a CanMessage for the On Light Address.
130     * @return CanMessage for Light ON
131     */    
132    public CanMessage getAddrOn(){
133        return addrOn.makeMessage(tc.getCanid());
134    }
135    
136    /**
137     * Get a CanMessage for the Off Light Address.
138     * @return CanMessage for Light OFF
139     */    
140    public CanMessage getAddrOff(){
141        return addrOff.makeMessage(tc.getCanid());
142    }
143    
144    /**
145     * {@inheritDoc}
146     */
147    @Override
148    public CanMessage getBeanOnMessage(){
149        return checkEvent(getAddrOn());
150    }
151
152    /**
153     * {@inheritDoc}
154     */
155    @Override
156    public CanMessage getBeanOffMessage(){
157        return checkEvent(getAddrOff());
158    }
159
160    /**
161     * {@inheritDoc}
162     */
163    @Override
164    public void dispose() {
165        tc.removeCanListener(this);
166        super.dispose();
167    }    
168    
169    private static final Logger log = LoggerFactory.getLogger(CbusLight.class);
170}