001package jmri.jmrix.powerline; 002 003import jmri.Turnout; 004import jmri.implementation.AbstractTurnout; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008/** 009 * Turnout implementation for X10. 010 * <p> 011 * This object doesn't listen to the serial communications. It should 012 * eventually, so it can track changes outside the program. 013 * <p> 014 * Within JMRI, only one Turnout object should besending messages to a turnout 015 * address; more than one Turnout object pointing to a single device is not 016 * allowed. 017 * 018 * Extend jmri.AbstractTurnout for powerline serial layouts 019 * 020 * @author Bob Jacobsen Copyright (C) 2003, 2006, 2007, 2008 Converted to 021 * multiple connection 022 * @author kcameron Copyright (C) 2011 023 */ 024public class SerialTurnout extends AbstractTurnout { 025 026 /** 027 * Create a Turnout object, with both system and user names. 028 * <p> 029 * 'systemName' was previously validated in SerialTurnoutManager 030 * @param systemName system name 031 * @param tc traffic controller 032 * @param userName user name 033 */ 034 public SerialTurnout(String systemName, SerialTrafficController tc, String userName) { 035 super(systemName, userName); 036 this.tc = tc; 037 // Convert to the two-part X10 address 038 housecode = tc.getAdapterMemo().getSerialAddress().x10HouseCodeAsValueFromSystemName(getSystemName()); 039 devicecode = tc.getAdapterMemo().getSerialAddress().x10DeviceCodeAsValueFromSystemName(getSystemName()); 040 } 041 042 private SerialTrafficController tc = null; 043 044 /** 045 * {@inheritDoc} 046 */ 047 @Override 048 protected void forwardCommandChangeToLayout(int newState) { 049 // implementing classes will typically have a function/listener to get 050 // updates from the layout, which will then call 051 // public void firePropertyChange(String propertyName, 052 // Object oldValue, 053 // Object newValue) 054 // _once_ if anything has changed state (or set the commanded state directly) 055 056 // sort out states 057 if ((newState & Turnout.CLOSED) != 0) { 058 // first look for the double case, which we can't handle 059 if ((newState & Turnout.THROWN) != 0) { 060 // this is the disaster case! 061 log.error("Cannot command both CLOSED and THROWN {}", newState); 062 return; 063 } else { 064 // send a CLOSED command 065 sendMessage(!getInverted()); 066 } 067 } else { 068 // send a THROWN command 069 sendMessage(getInverted()); 070 } 071 } 072 073 @Override 074 protected void turnoutPushbuttonLockout(boolean _pushButtonLockout) { 075 log.debug("Send command to {} Pushbutton", (_pushButtonLockout ? "Lock" : "Unlock")); 076 } 077 078 // data members holding the X10 address 079 int housecode = -1; 080 int devicecode = -1; 081 082 protected void sendMessage(boolean closed) { 083 if (log.isDebugEnabled()) { 084 log.debug("set closed {} house {} device {}", closed, X10Sequence.houseCodeToText(housecode), devicecode); 085 } 086 // create output sequence of address, then function 087 X10Sequence out = new X10Sequence(); 088 out.addAddress(housecode, devicecode); 089 out.addFunction(housecode, (closed ? X10Sequence.FUNCTION_OFF : X10Sequence.FUNCTION_ON), 0); 090 // send 091 tc.sendX10Sequence(out, null); 092 } 093 094 private final static Logger log = LoggerFactory.getLogger(SerialTurnout.class); 095 096}