001package jmri.jmris.srcp; 002 003import java.beans.PropertyChangeListener; 004import java.io.DataInputStream; 005import java.io.IOException; 006import java.io.OutputStream; 007 008import jmri.InstanceManager; 009import jmri.Sensor; 010import jmri.SensorManager; 011import jmri.jmris.AbstractSensorServer; 012import jmri.SystemConnectionMemo; 013 014/** 015 * SRCP Server interface between the JMRI Sensor manager and a network 016 * connection 017 * 018 * @author Paul Bender Copyright (C) 2011 019 */ 020public class JmriSRCPSensorServer extends AbstractSensorServer implements PropertyChangeListener { 021 022 private static final String ERROR = "Error499"; 023 private OutputStream output; 024 025 public JmriSRCPSensorServer(DataInputStream inStream, OutputStream outStream) { 026 super(); 027 output = outStream; 028 } 029 030 031 /* 032 * Protocol Specific Abstract Functions 033 */ 034 @Override 035 public void sendStatus(String sensorName, int Status) throws IOException { 036 int bus = 0; 037 int address = 0; 038 java.util.List<SystemConnectionMemo> list = InstanceManager.getList(SystemConnectionMemo.class); 039 for (SystemConnectionMemo memo : list) { 040 String prefix = memo.getSystemPrefix(); 041 if (sensorName.startsWith(prefix)) { 042 try { 043 address = Integer.parseInt(sensorName.substring(prefix.length() + 1)); 044 break; 045 } catch (NumberFormatException ne) { 046 // we expect this if the prefix doesn't match 047 } 048 } 049 bus++; 050 } 051 052 if (bus > list.size()) { 053 output.write(Bundle.getMessage(ERROR).getBytes()); 054 return; 055 } 056 057 if (Status == Sensor.ACTIVE) { 058 output.write(( "100 INFO " + bus + " FB " + address + " 1\n\r").getBytes()); 059 } else if (Status == Sensor.INACTIVE) { 060 output.write(("100 INFO " + bus + " FB " + address + " 0\n\r").getBytes()); 061 } else { 062 // unknown state 063 output.write( Bundle.getMessage("Error411").getBytes()); 064 } 065 066 } 067 068 public void sendStatus(int bus, int address) throws IOException { 069 log.debug("send Status called with bus {} and address {}",bus,address); 070 java.util.List<SystemConnectionMemo> list = InstanceManager.getList(SystemConnectionMemo.class); 071 SystemConnectionMemo memo; 072 try { 073 memo = list.get(bus); 074 } catch (java.lang.IndexOutOfBoundsException obe) { 075 output.write(Bundle.getMessage("Error412").getBytes()); 076 return; 077 } 078 String sensorName = memo.getSystemPrefix() 079 + "S" + address; 080 try { 081 int Status = InstanceManager.getDefault(SensorManager.class).provideSensor(sensorName).getKnownState(); 082 if (Status == Sensor.ACTIVE) { 083 output.write(("100 INFO " + bus + " FB " + address + " 1\n\r").getBytes()); 084 } else if (Status == Sensor.INACTIVE) { 085 output.write(("100 INFO " + bus + " FB " + address + " 0\n\r").getBytes()); 086 } else { 087 // unknown state 088 output.write(Bundle.getMessage("Error411").getBytes()); 089 } 090 } catch (IllegalArgumentException ex) { 091 log.warn("Failed to provide Sensor \"{}\" in sendStatus", sensorName); 092 } 093 } 094 095 @Override 096 public void sendErrorStatus(String sensorName) throws IOException { 097 output.write(Bundle.getMessage(ERROR).getBytes()); 098 } 099 100 @Override 101 public void parseStatus(String statusString) throws jmri.JmriException, java.io.IOException { 102 output.write(Bundle.getMessage(ERROR).getBytes()); 103 } 104 105 /* 106 * for SRCP, we're doing the parsing elsewhere, so we just need to build 107 * the correct string from the provided compoents. 108 */ 109 public void parseStatus(int bus, int address, int value) throws java.io.IOException { 110 log.debug("parse Status called with bus {} address {} and value {}",bus,address,value); 111 java.util.List<SystemConnectionMemo> list = InstanceManager.getList(SystemConnectionMemo.class); 112 SystemConnectionMemo memo; 113 try { 114 memo = list.get(bus - 1); 115 } catch (java.lang.IndexOutOfBoundsException obe) { 116 output.write("412 ERROR wrong value\n\r".getBytes()); 117 return; 118 } 119 String sensorName = memo.getSystemPrefix() 120 + "S" + address; 121 this.initSensor(sensorName); 122 if (value == 0) { 123 if (log.isDebugEnabled()) { 124 log.debug("Setting Sensor INACTIVE"); 125 } 126 setSensorInactive(sensorName); 127 } else if (value == 1) { 128 if (log.isDebugEnabled()) { 129 log.debug("Setting Sensor ACTIVE"); 130 } 131 setSensorActive(sensorName); 132 } 133 } 134 135 @Override 136 protected synchronized void addSensorToList(String sensorName) { 137 Sensor s = InstanceManager.getDefault(SensorManager.class).getSensor(sensorName); 138 if(s!=null) { 139 s.addPropertyChangeListener(this); 140 } 141 } 142 143 @Override 144 protected synchronized void removeSensorFromList(String sensorName) { 145 Sensor s = InstanceManager.getDefault(SensorManager.class).getSensor(sensorName); 146 if(s!=null) { 147 s.removePropertyChangeListener(this); 148 } 149 } 150 151 152 // update state as state of sensor changes 153 @Override 154 public void propertyChange(java.beans.PropertyChangeEvent e) { 155 // If the Commanded State changes, show transition state as "<inconsistent>" 156 if (e.getPropertyName().equals("KnownState")) { 157 try { 158 String Name = ((jmri.Sensor) e.getSource()).getSystemName(); 159 java.util.List<SystemConnectionMemo> memoList = InstanceManager.getList(SystemConnectionMemo.class); 160 int i = 0; 161 int address; 162 for (SystemConnectionMemo memo : memoList) { 163 String prefix = memo.getSystemPrefix(); 164 if (Name.startsWith(prefix)) { 165 address = Integer.parseInt(Name.substring(prefix.length()+1)); 166 sendStatus(i, address); 167 break; 168 } 169 i++; 170 } 171 } catch (java.io.IOException ie) { 172 log.error("Error Sending Status"); 173 } 174 } 175 } 176 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(JmriSRCPSensorServer.class); 177}