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}