001package jmri.jmrix.grapevine;
002
003import jmri.Turnout;
004import jmri.implementation.AbstractTurnout;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/**
009 * Implement Turnout for Grapevine.
010 * <p>
011 * This object doesn't listen to the Grapevine serial communications. This is
012 * because it should be the only object that is sending messages for this
013 * turnout; more than one Turnout object pointing to a single device is not
014 * allowed.
015 *
016 * @author Bob Jacobsen Copyright (C) 2003, 2006, 2007, 2008
017 */
018public class SerialTurnout extends AbstractTurnout {
019
020    GrapevineSystemConnectionMemo memo = null;
021
022    /**
023     * Create a Turnout object, with both system and user names.
024     *
025     * @param systemName system name including prefix, previously validated in SerialTurnoutManager
026     * @param userName free form name
027     * @param _memo the associated SystemConnectionMemo
028     */
029    public SerialTurnout(String systemName, String userName, GrapevineSystemConnectionMemo _memo) {
030        super(systemName, userName);
031        memo = _memo;
032        // Save systemName
033        tSystemName = systemName;
034        // Extract the Bit from the name
035        int num = SerialAddress.getBitFromSystemName(systemName, memo.getSystemPrefix()); // bit one is address zero
036        log.debug("SerialTurnout {} created, num: {} prefix: {}", systemName, num, memo.getSystemPrefix());
037        // num is 101-124, 201-224, 301-324, 401-424
038        output = (num % 100) - 1; // 0 - 23
039        bank = (num / 100) - 1;  // 0 - 3
040    }
041
042    /**
043     * Grapevine turnouts can invert their outputs.
044     */
045    @Override
046    public boolean canInvert() {
047        return true;
048    }
049
050    /**
051     * {@inheritDoc}
052     */
053    @Override
054    protected void forwardCommandChangeToLayout(int newState) {
055        try {
056            sendMessage(stateChangeCheck(newState));
057        } catch (IllegalArgumentException ex) {
058            log.error("new state invalid, Turnout not set");
059        }
060    }
061
062    @Override
063    protected void turnoutPushbuttonLockout(boolean _pushButtonLockout) {
064        log.debug("Send command to {} Pushbutton", (_pushButtonLockout ? "Lock" : "Unlock"));
065    }
066
067    // data members
068    String tSystemName; // System Name of this turnout
069    int output;         // output connector number, 0-23
070    int bank;           // bank number, 0-3
071
072    protected void sendMessage(boolean closed) {
073        SerialNode tNode = SerialAddress.getNodeFromSystemName(tSystemName, memo.getTrafficController());
074        if (tNode == null) {
075            // node does not exist, ignore call
076            log.error("Can't find node for {}, command ignored", tSystemName);
077            return;
078        }
079        boolean high = (output >= 12);
080        int tOut = output;
081        if (high) {
082            tOut = output - 12;
083        }
084        if ((bank < 0) || (bank > 4)) {
085            log.error("invalid bank {}  for Turnout {}", bank, getSystemName());
086            bank = 0;
087        }
088
089        SerialMessage m = new SerialMessage(high ? 8 : 4);
090        int i = 0;
091        if (high) {
092            m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 1
093            m.setElement(i++, 122);   // shift command
094            m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 2
095            m.setElement(i++, 0x10);  // bank 1
096            m.setParity(i - 4);
097        }
098        m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 1
099        m.setElement(i++, (tOut << 3) | (closed ? 0 : 6));  // closed is green, thrown is red
100        m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 2
101        m.setElement(i++, bank << 4); // bank is most significant bits
102        m.setParity(i - 4);
103        memo.getTrafficController().sendSerialMessage(m, null);
104    }
105
106    private final static Logger log = LoggerFactory.getLogger(SerialTurnout.class);
107
108}