001package jmri.jmrix.can.cbus;
002
003import jmri.implementation.DefaultCabSignal;
004import jmri.jmrix.can.CanSystemConnectionMemo;
005import jmri.jmrix.can.CanMessage;
006import jmri.jmrix.can.TrafficController;
007import jmri.LocoAddress;
008import jmri.SignalAppearanceMap;
009import jmri.SignalMast;
010
011/**
012 * CBUS implementation of a Cab Signal Object, describing the state of the 
013 * track ahead relative to a locomotive with a given address.  This is 
014 * effectively a mobile signal mast.
015 * <p>
016 * Uses an experimental MERG CBUS OPC
017 * todo - add semaphore flags
018 * todo - add loco speed / block speed
019 *
020 * @author Steve Young Copyright (C) 2018
021 * @author Paul Bender Copyright (C) 2019
022 */
023public class CbusCabSignal extends DefaultCabSignal {
024
025    private TrafficController tc;
026
027    public CbusCabSignal(CanSystemConnectionMemo memo,LocoAddress address){
028       super(address);
029       tc = memo.getTrafficController();
030       log.debug("created cab signal for {}",address);
031    }
032
033    /**
034     * A method for cleaning up the cab signal 
035     */
036    @Override
037    public void dispose(){
038        super.dispose();
039        tc=null;
040    }
041
042    /**
043     * Forward the command to the layout that sets the displayed signal
044     * aspect for this address
045     */
046    @Override
047    protected void forwardAspectToLayout(){
048        LocoAddress locoaddr = getCabSignalAddress();
049        SignalMast mast = getNextMast();
050
051        int locoAddr = locoaddr.getNumber();
052        if (locoaddr.getProtocol() == (LocoAddress.Protocol.DCC_LONG)) {
053            locoAddr |= 0xC000;
054        }
055        // Calculate the two byte loco address value
056        int locoD1 = locoAddr / 256;
057        int locoD2 = locoAddr & 0xff;
058
059        int sendAspect1 = 0xff; // default case, unknown.
060        int sendAspect2 = 0x00; 
061        int sendSpeed = 0xff; // default case, unknown.
062
063        if ( mast != null ) {
064            // String speed = (String) mast.getSignalSystem().getProperty(mast.getAspect(), "speed");
065            String aspect = mast.getAspect();
066            if ( aspect != null ) {
067                switch( aspect ) { // in a future java, add null to switch case
068                    case "Danger": // NOI18N
069                    case "On": // NOI18N
070                        sendAspect1 = 0;
071                        break;
072                    case "Caution": // NOI18N
073                        sendAspect1 = 1;
074                        break;
075                    case "Preliminary Caution": // NOI18N
076                        sendAspect1 = 2;
077                        break;
078                    case "Proceed": // NOI18N
079                        sendAspect1 = 3;
080                        break;
081                    case "Off": // NOI18N
082                        sendAspect1 = 4;
083                        break;
084                    case "Flash Caution": // NOI18N
085                        sendAspect1 = 1;
086                        sendAspect2 = 1;
087                        break;
088                    case "Flash Preliminary Caution": // NOI18N
089                        sendAspect1 = 2;
090                        sendAspect2 = 1;
091                        break;
092                    default: {
093                        // if no matching speed in the list above, check for
094                        // the constant values in the SignalAppearanceMap.
095                        if(aspect.equals(mast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.PERMISSIVE))){
096                            sendAspect1 = 0x04;
097                        } else if(aspect.equals(mast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER))){
098                            sendAspect1 = 0x00;
099                        } else if(aspect.equals(mast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.HELD))){
100                            sendAspect1 = 0x00;
101                        } else if(aspect.equals(mast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DARK))){
102                            sendAspect1 = 0x00; // show nothing;
103                        }
104                    }
105                }
106            }
107        }
108
109        CanMessage m = new CanMessage(7,tc.getCanid());
110        CbusMessage.setPri(m, CbusConstants.DEFAULT_DYNAMIC_PRIORITY * 4 + CbusConstants.DEFAULT_MINOR_PRIORITY);
111        m.setElement(0, CbusConstants.CBUS_CABDAT);
112        m.setElement(1, locoD1); // addr hi
113        m.setElement(2, locoD2);  // addr low
114        m.setElement(3, 1); // datcode type
115        m.setElement(4, ( sendAspect1 )); // aspect 1
116        m.setElement(5, ( sendAspect2 )); // aspect 2
117        m.setElement(6, ( sendSpeed ) ); // speed
118        tc.sendCanMessage(m, null);
119    }
120
121    /**
122     * Forward the command to the layout that clears any displayed signal
123     * for this address
124     */
125    @Override
126    protected void resetLayoutCabSignal(){
127        LocoAddress locoaddr = getCabSignalAddress();
128        int locoAddr = locoaddr.getNumber();
129        if (locoaddr.getProtocol()==(LocoAddress.Protocol.DCC_LONG)) {
130            locoAddr |= 0xC000;
131        }
132        // Calculate the two byte loco address value
133        int locoD1 = locoAddr / 256;
134        int locoD2 = locoAddr & 0xff;
135
136        CanMessage m = new CanMessage(7,tc.getCanid());
137        CbusMessage.setPri(m, CbusConstants.DEFAULT_DYNAMIC_PRIORITY * 4 + CbusConstants.DEFAULT_MINOR_PRIORITY);
138        m.setElement(0, CbusConstants.CBUS_CABDAT); // experimental cabdata opc
139        m.setElement(1, locoD1); // addr hi
140        m.setElement(2, locoD2);  // addr low
141        m.setElement(3, 1); // datcode type
142        m.setElement(4, ( 0xff )); // aspect 1
143        m.setElement(5, ( 0 )); // aspect 2
144        m.setElement(6, ( 0xff )); // speed
145        tc.sendCanMessage(m, null);
146    }
147
148    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CbusCabSignal.class);
149
150}