001package jmri.jmrix.grapevine;
002
003import jmri.implementation.AbstractLight;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007/**
008 * Implementation of the Light interface using Grapevine signal ports.
009 * <p>
010 * The "On" state results in sending a "green" setting to the hardware port;
011 * the "Off" state results in sending a "dark" setting to the hardware.
012 *
013 * @author Dave Duchamp Copyright (C) 2004
014 * @author Bob Jacobsen Copyright (C) 2006, 2007, 2008
015 */
016public class SerialLight extends AbstractLight {
017
018    private GrapevineSystemConnectionMemo memo = null;
019
020    /**
021     * Create a Light object, with only system name.
022     *
023     * @param systemName system name including prefix, previously validated in SerialLightManager
024     * @param _memo the associated SystemConnectionMemo
025     */
026    public SerialLight(String systemName, GrapevineSystemConnectionMemo _memo) {
027        super(systemName);
028        memo = _memo;
029        // Initialize the Light
030        initializeLight(systemName);
031    }
032
033    /**
034     * Create a Light object, with both system and user names.
035     *
036     * @param systemName system name including prefix, previously validated in SerialLightManager
037     * @param userName free form name
038     * @param _memo the associated SystemConnectionMemo
039     */
040    public SerialLight(String systemName, String userName, GrapevineSystemConnectionMemo _memo) {
041        super(systemName, userName);
042        memo = _memo;
043        initializeLight(systemName);
044    }
045
046    /**
047     * Set up system dependent instance variables and set system independent
048     * instance variables to default values.
049     * <p>
050     * Note: most instance variables are in AbstractLight.java
051     */
052    private void initializeLight(String systemName) {
053        // Extract the Bit from the name
054        int num = SerialAddress.getBitFromSystemName(systemName, memo.getSystemPrefix()); // bit one is address zero
055        // num is 101-124, 201-224, 301-324, 401-424
056        output = (num % 100) - 1; // 0-23
057        bank = (num / 100) - 1;  // 0 - 3
058
059        // Set initial state to OFF internally and on layout
060        setState(OFF);
061    }
062
063    /**
064     * System dependent instance variables
065     */
066    int output;         // output connector number, 0-23
067    int bank;           // bank number, 0-3
068
069    /**
070     * Set the current state of this Light. This routine requests the hardware to
071     * change. If this is really a change in state of this bit (tested in
072     * SerialNode), a Transmit packet will be sent before this Node is next
073     * polled.
074     */
075    @Override
076    protected void doNewState(int oldState, int newState) {
077        SerialNode mNode = SerialAddress.getNodeFromSystemName(getSystemName(), memo.getTrafficController());
078        if (mNode != null) {
079            if (newState == ON) {
080                sendMessage(true);
081            } else if (newState == OFF) {
082                sendMessage(false);
083            } else {
084                log.warn("illegal state requested for Light: {}", getSystemName());
085            }
086        }
087    }
088
089    protected void sendMessage(boolean on) {
090        SerialNode tNode = SerialAddress.getNodeFromSystemName(getSystemName(), memo.getTrafficController());
091        if (tNode == null) {
092            // node does not exist, ignore call
093            log.error("Can't find node for {}, command ignored", getSystemName());
094            return;
095        }
096        boolean high = (output >= 12);
097        int tOut = output;
098        if (high) {
099            tOut = output - 12;
100        }
101        if ((bank < 0) || (bank > 4)) {
102            log.error("invalid bank {}  for Light {}", bank, getSystemName());
103            bank = 0;
104        }
105        SerialMessage m = new SerialMessage(high ? 8 : 4);
106        int i = 0;
107        if (high) {
108            m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 1
109            m.setElement(i++, 122);   // shift command
110            m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 2
111            m.setElement(i++, 0x10);  // bank 1
112            m.setParity(i - 4);
113        }
114        m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 1
115        m.setElement(i++, (tOut << 3) | (on ? 0 : 4));  // on is green, off is dark
116        m.setElement(i++, tNode.getNodeAddress() | 0x80);  // address 2
117        m.setElement(i++, bank << 4); // bank is most significant bits
118        m.setParity(i - 4);
119        memo.getTrafficController().sendSerialMessage(m, null);
120    }
121
122    private final static Logger log = LoggerFactory.getLogger(SerialLight.class);
123
124}