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