001package jmri.jmrix.grapevine;
002
003import jmri.implementation.DefaultSignalHead;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007/**
008 * Extend jmri.AbstractSignalHead for grapevine serial signals.
009 *
010 * This object doesn't listen to the Grapevine serial communications. It
011 * probably should, however, in case.
012 *
013 * @author Bob Jacobsen Copyright (C) 2003, 2006, 2007
014 */
015public class SerialSignalHead extends DefaultSignalHead {
016
017    GrapevineSystemConnectionMemo memo = null;
018
019    /**
020     * Create a SignalHead object, with only system name.
021     *
022     * @param systemName system name including prefix, should have ben previously validated
023     * @param _memo the associated SystemConnectionMemo
024     */
025    public SerialSignalHead(String systemName, GrapevineSystemConnectionMemo _memo) {
026        super(systemName);
027        memo = _memo;
028        // Save system Name
029        tSystemName = systemName;
030        // Extract the Bit from the name
031        int num = SerialAddress.getBitFromSystemName(systemName, memo.getSystemPrefix()); // bit one is address zero
032        // num is 101-124, 201-224, 301-324, 401-424
033        output = (num % 100) - 1; // 0-23
034        bank = (num / 100) - 1;  // 0 - 3
035    }
036
037    /**
038     * Create a SignalHead object, with both system and user names.
039     *
040     * @param systemName system name including prefix, should have ben previously validated
041     * @param userName free form name
042     * @param _memo the associated SystemConnectionMemo
043     */
044    public SerialSignalHead(String systemName, String userName, GrapevineSystemConnectionMemo _memo) {
045        super(systemName, userName);
046        memo = _memo;
047        // Save system Name
048        tSystemName = systemName;
049        // Extract the Bit from the name
050        int num = SerialAddress.getBitFromSystemName(systemName, memo.getSystemPrefix()); // bit one is address zero
051        // num is 101-124, 201-224, 301-324, 401-424
052        output = (num % 100) - 1; // 0-23
053        bank = (num / 100) - 1;  // 0 - 3
054    }
055
056    /**
057     * Handle a request to change state on layout
058     */
059    @Override
060    protected void updateOutput() {
061        SerialNode tNode = SerialAddress.getNodeFromSystemName(tSystemName, memo.getTrafficController());
062        if (tNode == null) {
063            // node does not exist, ignore call
064            log.error("Can't find node for {}, command ignored", tSystemName);
065            return;
066        }
067
068        boolean high = (output >= 12);
069        int tOut = output;
070        if (high) {
071            tOut = output - 12;
072        }
073        if ((bank < 0) || (bank > 4)) {
074            log.error("invalid bank {} for signal {}", bank, getSystemName());
075            bank = 0;
076        }
077
078        // sort out states
079        int cmd;
080        if (mLit) {
081            switch (mAppearance) {
082                case RED:
083                    cmd = 6;
084                    break;
085                case FLASHRED:
086                    cmd = 7;
087                    break;
088                case YELLOW:
089                    cmd = 2;
090                    break;
091                case FLASHYELLOW:
092                    cmd = 3;
093                    break;
094                case GREEN:
095                    cmd = 0;
096                    break;
097                case FLASHGREEN:
098                    cmd = 1;
099                    break;
100                case DARK:
101                    cmd = 4;
102                    break;
103                default:
104                    log.warn("Unexpected new appearance: {}", mAppearance);
105                    cmd = 7;
106                    break;  // flash red for error
107            }
108        } else {
109            cmd = 4; // set dark if not lit
110        }
111
112        SerialMessage m = new SerialMessage(high ? 8 : 4);
113        int i = 0;
114        if (high) {
115            m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 1
116            m.setElement(i++, 122);   // shift command
117            m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 2
118            m.setElement(i++, 0x10);  // bank 1
119            m.setParity(i - 4);
120        }
121        m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 1
122        m.setElement(i++, (tOut << 3) | cmd);
123        m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 2
124        m.setElement(i++, bank << 4); // bank is most significant bits
125        m.setParity(i - 4);
126        memo.getTrafficController().sendSerialMessage(m, null);
127    }
128
129    // flashing is done on the cards, so we don't have to
130    // do it manually
131    @Override
132    public void startFlash() {
133    }
134
135    @Override
136    public void stopFlash() {
137    }
138
139    // data members
140    String tSystemName; // System Name of this signal head
141    int output;         // output connector number, 0-23
142    int bank;           // bank number, 0-3
143
144    private final static Logger log = LoggerFactory.getLogger(SerialSignalHead.class);
145
146}