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}