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